Add initial support for wide symbols
[bpt/guile.git] / libguile / strings.c
CommitLineData
50b1996f 1/* Copyright (C) 1995,1996,1998,2000,2001, 2004, 2006, 2008, 2009 Free Software Foundation, Inc.
0f2d19dd 2 *
73be1d9e 3 * This library is free software; you can redistribute it and/or
53befeb7
NJ
4 * modify it under the terms of the GNU Lesser General Public License
5 * as published by the Free Software Foundation; either version 3 of
6 * the License, or (at your option) any later version.
0f2d19dd 7 *
53befeb7
NJ
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
73be1d9e
MV
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
0f2d19dd 12 *
73be1d9e
MV
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
53befeb7
NJ
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16 * 02110-1301 USA
73be1d9e 17 */
1bbd0b84 18
1bbd0b84 19
0f2d19dd 20\f
dbb605f5
LC
21#ifdef HAVE_CONFIG_H
22# include <config.h>
23#endif
0f2d19dd 24
faf2c9d7 25#include <string.h>
3ee86942 26#include <stdio.h>
9c44cd45
MG
27#include <ctype.h>
28#include <unistr.h>
eca29b02 29#include <uniconv.h>
faf2c9d7 30
a0599745
MD
31#include "libguile/_scm.h"
32#include "libguile/chars.h"
7c33806a 33#include "libguile/root.h"
a0599745 34#include "libguile/strings.h"
1afff620 35#include "libguile/deprecation.h"
a0599745 36#include "libguile/validate.h"
c829a427 37#include "libguile/dynwind.h"
1afff620 38
0f2d19dd
JB
39\f
40
41/* {Strings}
42 */
43
3ee86942
MV
44
45/* Stringbufs
46 *
47 * XXX - keeping an accurate refcount during GC seems to be quite
48 * tricky, so we just keep score of whether a stringbuf might be
50b1996f 49 * shared, not whether it definitely is.
3ee86942
MV
50 *
51 * The scheme I (mvo) tried to keep an accurate reference count would
52 * recount all strings that point to a stringbuf during the mark-phase
53 * of the GC. This was done since one cannot access the stringbuf of
54 * a string when that string is freed (in order to decrease the
55 * reference count). The memory of the stringbuf might have been
56 * reused already for something completely different.
57 *
58 * This recounted worked for a small number of threads beating on
59 * cow-strings, but it failed randomly with more than 10 threads, say.
60 * I couldn't figure out what went wrong, so I used the conservative
61 * approach implemented below.
62 *
63 * A stringbuf needs to know its length, but only so that it can be
64 * reported when the stringbuf is freed.
65 *
50b1996f
MG
66 * There are 3 storage strategies for stringbufs: inline, outline, and
67 * wide.
68 *
69 * Inline strings are small 8-bit strings stored within the double
70 * cell itself. Outline strings are larger 8-bit strings with GC
71 * allocated storage. Wide strings are 32-bit strings with allocated
72 * storage.
73 *
74 * There was little value in making wide string inlineable, since
75 * there is only room for three inlined 32-bit characters. Thus wide
76 * stringbufs are never inlined.
3ee86942
MV
77 */
78
79#define STRINGBUF_F_SHARED 0x100
80#define STRINGBUF_F_INLINE 0x200
50b1996f
MG
81#define STRINGBUF_F_WIDE 0x400 /* If true, strings have UCS-4
82 encoding. Otherwise, strings
83 are Latin-1. */
3ee86942
MV
84
85#define STRINGBUF_TAG scm_tc7_stringbuf
86#define STRINGBUF_SHARED(buf) (SCM_CELL_WORD_0(buf) & STRINGBUF_F_SHARED)
87#define STRINGBUF_INLINE(buf) (SCM_CELL_WORD_0(buf) & STRINGBUF_F_INLINE)
9c44cd45 88#define STRINGBUF_WIDE(buf) (SCM_CELL_WORD_0(buf) & STRINGBUF_F_WIDE)
3ee86942 89
f59cf998 90#define STRINGBUF_OUTLINE_CHARS(buf) ((unsigned char *) SCM_CELL_WORD_1(buf))
3ee86942 91#define STRINGBUF_OUTLINE_LENGTH(buf) (SCM_CELL_WORD_2(buf))
f59cf998 92#define STRINGBUF_INLINE_CHARS(buf) ((unsigned char *) SCM_CELL_OBJECT_LOC(buf,1))
3ee86942
MV
93#define STRINGBUF_INLINE_LENGTH(buf) (((size_t)SCM_CELL_WORD_0(buf))>>16)
94
95#define STRINGBUF_CHARS(buf) (STRINGBUF_INLINE (buf) \
96 ? STRINGBUF_INLINE_CHARS (buf) \
97 : STRINGBUF_OUTLINE_CHARS (buf))
50b1996f 98
f59cf998 99#define STRINGBUF_WIDE_CHARS(buf) ((scm_t_wchar *) SCM_CELL_WORD_1(buf))
3ee86942
MV
100#define STRINGBUF_LENGTH(buf) (STRINGBUF_INLINE (buf) \
101 ? STRINGBUF_INLINE_LENGTH (buf) \
102 : STRINGBUF_OUTLINE_LENGTH (buf))
103
104#define STRINGBUF_MAX_INLINE_LEN (3*sizeof(scm_t_bits))
105
106#define SET_STRINGBUF_SHARED(buf) \
107 (SCM_SET_CELL_WORD_0 ((buf), SCM_CELL_WORD_0 (buf) | STRINGBUF_F_SHARED))
108
6ce6923b 109#if SCM_STRING_LENGTH_HISTOGRAM
3ee86942
MV
110static size_t lenhist[1001];
111#endif
112
50b1996f
MG
113/* Make a stringbuf with space for LEN 8-bit Latin-1-encoded
114 characters. */
3ee86942
MV
115static SCM
116make_stringbuf (size_t len)
0f2d19dd 117{
3ee86942
MV
118 /* XXX - for the benefit of SCM_STRING_CHARS, SCM_SYMBOL_CHARS and
119 scm_i_symbol_chars, all stringbufs are null-terminated. Once
120 SCM_STRING_CHARS and SCM_SYMBOL_CHARS are removed and the code
121 has been changed for scm_i_symbol_chars, this null-termination
122 can be dropped.
123 */
124
6ce6923b 125#if SCM_STRING_LENGTH_HISTOGRAM
3ee86942
MV
126 if (len < 1000)
127 lenhist[len]++;
128 else
129 lenhist[1000]++;
130#endif
0f2d19dd 131
3ee86942
MV
132 if (len <= STRINGBUF_MAX_INLINE_LEN-1)
133 {
134 return scm_double_cell (STRINGBUF_TAG | STRINGBUF_F_INLINE | (len << 16),
135 0, 0, 0);
136 }
137 else
138 {
139 char *mem = scm_gc_malloc (len+1, "string");
140 mem[len] = '\0';
141 return scm_double_cell (STRINGBUF_TAG, (scm_t_bits) mem,
142 (scm_t_bits) len, (scm_t_bits) 0);
143 }
144}
e53cc817 145
50b1996f
MG
146/* Make a stringbuf with space for LEN 32-bit UCS-4-encoded
147 characters. */
9c44cd45
MG
148static SCM
149make_wide_stringbuf (size_t len)
150{
151 scm_t_wchar *mem;
6ce6923b 152#if SCM_STRING_LENGTH_HISTOGRAM
9c44cd45
MG
153 if (len < 1000)
154 lenhist[len]++;
155 else
156 lenhist[1000]++;
157#endif
158
159 mem = scm_gc_malloc (sizeof (scm_t_wchar) * (len + 1), "string");
160 mem[len] = 0;
161 return scm_double_cell (STRINGBUF_TAG | STRINGBUF_F_WIDE, (scm_t_bits) mem,
162 (scm_t_bits) len, (scm_t_bits) 0);
163}
164
2b829bbb
KR
165/* Return a new stringbuf whose underlying storage consists of the LEN+1
166 octets pointed to by STR (the last octet is zero). */
7f74cf9a 167SCM
fd0a5bbc
HWN
168scm_i_take_stringbufn (char *str, size_t len)
169{
2b829bbb 170 scm_gc_register_collectable_memory (str, len + 1, "stringbuf");
fd0a5bbc
HWN
171
172 return scm_double_cell (STRINGBUF_TAG, (scm_t_bits) str,
173 (scm_t_bits) len, (scm_t_bits) 0);
174}
175
3ee86942
MV
176SCM
177scm_i_stringbuf_mark (SCM buf)
178{
179 return SCM_BOOL_F;
180}
1bbd0b84 181
3ee86942
MV
182void
183scm_i_stringbuf_free (SCM buf)
0f2d19dd 184{
3ee86942 185 if (!STRINGBUF_INLINE (buf))
9c44cd45
MG
186 {
187 if (!STRINGBUF_WIDE (buf))
188 scm_gc_free (STRINGBUF_OUTLINE_CHARS (buf),
189 STRINGBUF_OUTLINE_LENGTH (buf) + 1, "string");
190 else
191 scm_gc_free (STRINGBUF_OUTLINE_CHARS (buf),
192 sizeof (scm_t_wchar) * (STRINGBUF_OUTLINE_LENGTH (buf)
193 + 1), "string");
194 }
195
196}
197
50b1996f
MG
198/* Convert a stringbuf containing 8-bit Latin-1-encoded characters to
199 one containing 32-bit UCS-4-encoded characters. */
9c44cd45
MG
200static void
201widen_stringbuf (SCM buf)
202{
203 size_t i, len;
204 scm_t_wchar *mem;
205
206 if (STRINGBUF_WIDE (buf))
207 return;
208
209 if (STRINGBUF_INLINE (buf))
210 {
211 len = STRINGBUF_INLINE_LENGTH (buf);
212
213 mem = scm_gc_malloc (sizeof (scm_t_wchar) * (len + 1), "string");
214 for (i = 0; i < len; i++)
215 mem[i] =
f59cf998 216 (scm_t_wchar) STRINGBUF_INLINE_CHARS (buf)[i];
9c44cd45
MG
217 mem[len] = 0;
218
219 SCM_SET_CELL_WORD_0 (buf, SCM_CELL_WORD_0 (buf) ^ STRINGBUF_F_INLINE);
220 SCM_SET_CELL_WORD_0 (buf, SCM_CELL_WORD_0 (buf) | STRINGBUF_F_WIDE);
221 SCM_SET_CELL_WORD_1 (buf, mem);
222 SCM_SET_CELL_WORD_2 (buf, len);
223 }
224 else
225 {
226 len = STRINGBUF_OUTLINE_LENGTH (buf);
227
228 mem = scm_gc_malloc (sizeof (scm_t_wchar) * (len + 1), "string");
229 for (i = 0; i < len; i++)
230 mem[i] =
f59cf998 231 (scm_t_wchar) STRINGBUF_OUTLINE_CHARS (buf)[i];
9c44cd45
MG
232 mem[len] = 0;
233
234 scm_gc_free (STRINGBUF_OUTLINE_CHARS (buf), len + 1, "string");
235
236 SCM_SET_CELL_WORD_0 (buf, SCM_CELL_WORD_0 (buf) | STRINGBUF_F_WIDE);
237 SCM_SET_CELL_WORD_1 (buf, mem);
238 SCM_SET_CELL_WORD_2 (buf, len);
239 }
3ee86942 240}
bd9e24b3 241
9de87eea 242scm_i_pthread_mutex_t stringbuf_write_mutex = SCM_I_PTHREAD_MUTEX_INITIALIZER;
bd9e24b3 243
3ee86942
MV
244/* Copy-on-write strings.
245 */
bd9e24b3 246
3ee86942 247#define STRING_TAG scm_tc7_string
bd9e24b3 248
3ee86942
MV
249#define STRING_STRINGBUF(str) (SCM_CELL_OBJECT_1(str))
250#define STRING_START(str) ((size_t)SCM_CELL_WORD_2(str))
251#define STRING_LENGTH(str) ((size_t)SCM_CELL_WORD_3(str))
bd9e24b3 252
3ee86942
MV
253#define SET_STRING_STRINGBUF(str,buf) (SCM_SET_CELL_OBJECT_1(str,buf))
254#define SET_STRING_START(str,start) (SCM_SET_CELL_WORD_2(str,start))
255
256#define IS_STRING(str) (SCM_NIMP(str) && SCM_TYP7(str) == STRING_TAG)
257
ed35de72
MV
258/* Read-only strings.
259 */
260
261#define RO_STRING_TAG (scm_tc7_string + 0x200)
262#define IS_RO_STRING(str) (SCM_CELL_TYPE(str)==RO_STRING_TAG)
263
e1b29f6a
MV
264/* Mutation-sharing substrings
265 */
266
267#define SH_STRING_TAG (scm_tc7_string + 0x100)
268
269#define SH_STRING_STRING(sh) (SCM_CELL_OBJECT_1(sh))
270/* START and LENGTH as for STRINGs. */
271
272#define IS_SH_STRING(str) (SCM_CELL_TYPE(str)==SH_STRING_TAG)
273
50b1996f
MG
274/* Create a scheme string with space for LEN 8-bit Latin-1-encoded
275 characters. CHARSP, if not NULL, will be set to location of the
276 char array. */
3ee86942
MV
277SCM
278scm_i_make_string (size_t len, char **charsp)
279{
280 SCM buf = make_stringbuf (len);
281 SCM res;
282 if (charsp)
f59cf998 283 *charsp = (char *) STRINGBUF_CHARS (buf);
3ee86942
MV
284 res = scm_double_cell (STRING_TAG, SCM_UNPACK(buf),
285 (scm_t_bits)0, (scm_t_bits) len);
286 return res;
0f2d19dd
JB
287}
288
50b1996f
MG
289/* Create a scheme string with space for LEN 32-bit UCS-4-encoded
290 characters. CHARSP, if not NULL, will be set to location of the
291 character array. */
9c44cd45 292SCM
50b1996f 293scm_i_make_wide_string (size_t len, scm_t_wchar **charsp)
9c44cd45
MG
294{
295 SCM buf = make_wide_stringbuf (len);
296 SCM res;
297 if (charsp)
298 *charsp = STRINGBUF_WIDE_CHARS (buf);
299 res = scm_double_cell (STRING_TAG, SCM_UNPACK (buf),
300 (scm_t_bits) 0, (scm_t_bits) len);
301 return res;
302}
303
3ee86942
MV
304static void
305validate_substring_args (SCM str, size_t start, size_t end)
306{
307 if (!IS_STRING (str))
308 scm_wrong_type_arg_msg (NULL, 0, str, "string");
309 if (start > STRING_LENGTH (str))
310 scm_out_of_range (NULL, scm_from_size_t (start));
311 if (end > STRING_LENGTH (str) || end < start)
312 scm_out_of_range (NULL, scm_from_size_t (end));
313}
0f2d19dd 314
e1b29f6a
MV
315static inline void
316get_str_buf_start (SCM *str, SCM *buf, size_t *start)
317{
318 *start = STRING_START (*str);
319 if (IS_SH_STRING (*str))
320 {
321 *str = SH_STRING_STRING (*str);
322 *start += STRING_START (*str);
323 }
324 *buf = STRING_STRINGBUF (*str);
325}
326
3ee86942
MV
327SCM
328scm_i_substring (SCM str, size_t start, size_t end)
0f2d19dd 329{
e1b29f6a
MV
330 SCM buf;
331 size_t str_start;
332 get_str_buf_start (&str, &buf, &str_start);
9de87eea 333 scm_i_pthread_mutex_lock (&stringbuf_write_mutex);
3ee86942 334 SET_STRINGBUF_SHARED (buf);
9de87eea 335 scm_i_pthread_mutex_unlock (&stringbuf_write_mutex);
3ee86942 336 return scm_double_cell (STRING_TAG, SCM_UNPACK(buf),
e1b29f6a
MV
337 (scm_t_bits)str_start + start,
338 (scm_t_bits) end - start);
0f2d19dd
JB
339}
340
ed35de72
MV
341SCM
342scm_i_substring_read_only (SCM str, size_t start, size_t end)
343{
45a9f430
LC
344 SCM buf;
345 size_t str_start;
346 get_str_buf_start (&str, &buf, &str_start);
347 scm_i_pthread_mutex_lock (&stringbuf_write_mutex);
348 SET_STRINGBUF_SHARED (buf);
349 scm_i_pthread_mutex_unlock (&stringbuf_write_mutex);
350 return scm_double_cell (RO_STRING_TAG, SCM_UNPACK(buf),
351 (scm_t_bits)str_start + start,
352 (scm_t_bits) end - start);
ed35de72
MV
353}
354
3ee86942
MV
355SCM
356scm_i_substring_copy (SCM str, size_t start, size_t end)
357{
358 size_t len = end - start;
edea856c 359 SCM buf, my_buf;
e1b29f6a
MV
360 size_t str_start;
361 get_str_buf_start (&str, &buf, &str_start);
9c44cd45
MG
362 if (scm_i_is_narrow_string (str))
363 {
364 my_buf = make_stringbuf (len);
365 memcpy (STRINGBUF_CHARS (my_buf),
366 STRINGBUF_CHARS (buf) + str_start + start, len);
367 }
368 else
369 {
370 my_buf = make_wide_stringbuf (len);
371 u32_cpy ((scm_t_uint32 *) STRINGBUF_WIDE_CHARS (my_buf),
372 (scm_t_uint32 *) (STRINGBUF_WIDE_CHARS (buf) + str_start
373 + start), len);
374 /* Even though this string is wide, the substring may be narrow.
50b1996f 375 Consider adding code to narrow the string. */
9c44cd45 376 }
3ee86942 377 scm_remember_upto_here_1 (buf);
9c44cd45
MG
378 return scm_double_cell (STRING_TAG, SCM_UNPACK (my_buf),
379 (scm_t_bits) 0, (scm_t_bits) len);
3ee86942 380}
0f2d19dd 381
e1b29f6a
MV
382SCM
383scm_i_substring_shared (SCM str, size_t start, size_t end)
384{
385 if (start == 0 && end == STRING_LENGTH (str))
386 return str;
387 else
388 {
389 size_t len = end - start;
390 if (IS_SH_STRING (str))
391 {
392 start += STRING_START (str);
393 str = SH_STRING_STRING (str);
394 }
395 return scm_double_cell (SH_STRING_TAG, SCM_UNPACK(str),
396 (scm_t_bits)start, (scm_t_bits) len);
397 }
398}
399
3ee86942
MV
400SCM
401scm_c_substring (SCM str, size_t start, size_t end)
402{
403 validate_substring_args (str, start, end);
404 return scm_i_substring (str, start, end);
405}
ee149d03 406
ed35de72
MV
407SCM
408scm_c_substring_read_only (SCM str, size_t start, size_t end)
409{
410 validate_substring_args (str, start, end);
411 return scm_i_substring_read_only (str, start, end);
412}
413
0f2d19dd 414SCM
3ee86942 415scm_c_substring_copy (SCM str, size_t start, size_t end)
0f2d19dd 416{
3ee86942
MV
417 validate_substring_args (str, start, end);
418 return scm_i_substring_copy (str, start, end);
419}
420
3ee86942
MV
421SCM
422scm_c_substring_shared (SCM str, size_t start, size_t end)
423{
424 validate_substring_args (str, start, end);
425 return scm_i_substring_shared (str, start, end);
426}
0f2d19dd 427
ee149d03 428SCM
3ee86942 429scm_i_string_mark (SCM str)
ee149d03 430{
3ee86942
MV
431 if (IS_SH_STRING (str))
432 return SH_STRING_STRING (str);
433 else
434 return STRING_STRINGBUF (str);
ee149d03
JB
435}
436
3ee86942
MV
437void
438scm_i_string_free (SCM str)
439{
440}
36284627 441
3ee86942
MV
442/* Internal accessors
443 */
444
50b1996f
MG
445/* Returns the number of characters in STR. This may be different
446 than the memory size of the string storage. */
3ee86942
MV
447size_t
448scm_i_string_length (SCM str)
0f2d19dd 449{
3ee86942 450 return STRING_LENGTH (str);
0f2d19dd
JB
451}
452
50b1996f
MG
453/* True if the string is 'narrow', meaning it has a 8-bit Latin-1
454 encoding. False if it is 'wide', having a 32-bit UCS-4
455 encoding. */
9c44cd45
MG
456int
457scm_i_is_narrow_string (SCM str)
458{
459 return !STRINGBUF_WIDE (STRING_STRINGBUF (str));
460}
461
50b1996f
MG
462/* Returns a pointer to the 8-bit Latin-1 encoded character array of
463 STR. */
3ee86942
MV
464const char *
465scm_i_string_chars (SCM str)
466{
467 SCM buf;
e1b29f6a
MV
468 size_t start;
469 get_str_buf_start (&str, &buf, &start);
9c44cd45 470 if (scm_i_is_narrow_string (str))
f59cf998 471 return (const char *) STRINGBUF_CHARS (buf) + start;
9c44cd45
MG
472 else
473 scm_misc_error (NULL, "Invalid read access of chars of wide string: ~s",
474 scm_list_1 (str));
475 return NULL;
3ee86942 476}
b00418df 477
50b1996f
MG
478/* Returns a pointer to the 32-bit UCS-4 encoded character array of
479 STR. */
9c44cd45
MG
480const scm_t_wchar *
481scm_i_string_wide_chars (SCM str)
482{
483 SCM buf;
484 size_t start;
485
486 get_str_buf_start (&str, &buf, &start);
487 if (!scm_i_is_narrow_string (str))
f59cf998 488 return (const scm_t_wchar *) STRINGBUF_WIDE_CHARS (buf) + start;
9c44cd45
MG
489 else
490 scm_misc_error (NULL, "Invalid read access of chars of narrow string: ~s",
491 scm_list_1 (str));
492}
493
494/* If the buffer in ORIG_STR is shared, copy ORIG_STR's characters to
495 a new string buffer, so that it can be modified without modifying
50b1996f
MG
496 other strings. Also, lock the string mutex. Later, one must call
497 scm_i_string_stop_writing to unlock the mutex. */
9c44cd45
MG
498SCM
499scm_i_string_start_writing (SCM orig_str)
b00418df 500{
ed35de72 501 SCM buf, str = orig_str;
e1b29f6a 502 size_t start;
ed35de72 503
e1b29f6a 504 get_str_buf_start (&str, &buf, &start);
ed35de72
MV
505 if (IS_RO_STRING (str))
506 scm_misc_error (NULL, "string is read-only: ~s", scm_list_1 (orig_str));
507
9de87eea 508 scm_i_pthread_mutex_lock (&stringbuf_write_mutex);
3ee86942
MV
509 if (STRINGBUF_SHARED (buf))
510 {
9c44cd45 511 /* Clone the stringbuf. */
3ee86942
MV
512 size_t len = STRING_LENGTH (str);
513 SCM new_buf;
514
9de87eea 515 scm_i_pthread_mutex_unlock (&stringbuf_write_mutex);
3ee86942 516
9c44cd45
MG
517 if (scm_i_is_narrow_string (str))
518 {
519 new_buf = make_stringbuf (len);
520 memcpy (STRINGBUF_CHARS (new_buf),
521 STRINGBUF_CHARS (buf) + STRING_START (str), len);
522
523 }
524 else
525 {
526 new_buf = make_wide_stringbuf (len);
527 u32_cpy ((scm_t_uint32 *) STRINGBUF_WIDE_CHARS (new_buf),
528 (scm_t_uint32 *) (STRINGBUF_WIDE_CHARS (buf)
529 + STRING_START (str)), len);
530 }
3ee86942
MV
531 scm_i_thread_put_to_sleep ();
532 SET_STRING_STRINGBUF (str, new_buf);
533 start -= STRING_START (str);
534 SET_STRING_START (str, 0);
535 scm_i_thread_wake_up ();
536
537 buf = new_buf;
538
9de87eea 539 scm_i_pthread_mutex_lock (&stringbuf_write_mutex);
3ee86942 540 }
9c44cd45
MG
541 return orig_str;
542}
543
50b1996f 544/* Return a pointer to the 8-bit Latin-1 chars of a string. */
9c44cd45
MG
545char *
546scm_i_string_writable_chars (SCM str)
547{
548 SCM buf;
549 size_t start;
3ee86942 550
9c44cd45
MG
551 get_str_buf_start (&str, &buf, &start);
552 if (scm_i_is_narrow_string (str))
f59cf998 553 return (char *) STRINGBUF_CHARS (buf) + start;
9c44cd45
MG
554 else
555 scm_misc_error (NULL, "Invalid write access of chars of wide string: ~s",
556 scm_list_1 (str));
557 return NULL;
558}
559
50b1996f 560/* Return a pointer to the UCS-4 codepoints of a string. */
9c44cd45
MG
561static scm_t_wchar *
562scm_i_string_writable_wide_chars (SCM str)
563{
564 SCM buf;
565 size_t start;
566
567 get_str_buf_start (&str, &buf, &start);
568 if (!scm_i_is_narrow_string (str))
569 return STRINGBUF_WIDE_CHARS (buf) + start;
570 else
1c7b216f 571 scm_misc_error (NULL, "Invalid write access of chars of narrow string: ~s",
9c44cd45 572 scm_list_1 (str));
b00418df
DH
573}
574
50b1996f
MG
575/* Unlock the string mutex that was locked when
576 scm_i_string_start_writing was called. */
3ee86942
MV
577void
578scm_i_string_stop_writing (void)
579{
9de87eea 580 scm_i_pthread_mutex_unlock (&stringbuf_write_mutex);
3ee86942 581}
b00418df 582
50b1996f 583/* Return the Xth character of STR as a UCS-4 codepoint. */
9c44cd45
MG
584scm_t_wchar
585scm_i_string_ref (SCM str, size_t x)
586{
587 if (scm_i_is_narrow_string (str))
588 return (scm_t_wchar) (unsigned char) (scm_i_string_chars (str)[x]);
589 else
590 return scm_i_string_wide_chars (str)[x];
591}
592
50b1996f 593/* Set the Pth character of STR to UCS-4 codepoint CHR. */
9c44cd45
MG
594void
595scm_i_string_set_x (SCM str, size_t p, scm_t_wchar chr)
596{
597 if (chr > 0xFF && scm_i_is_narrow_string (str))
598 widen_stringbuf (STRING_STRINGBUF (str));
599
600 if (scm_i_is_narrow_string (str))
601 {
602 char *dst = scm_i_string_writable_chars (str);
603 dst[p] = (char) (unsigned char) chr;
604 }
605 else
606 {
607 scm_t_wchar *dst = scm_i_string_writable_wide_chars (str);
608 dst[p] = chr;
609 }
610}
611
3ee86942
MV
612/* Symbols.
613
614 Basic symbol creation and accessing is done here, the rest is in
615 symbols.[hc]. This has been done to keep stringbufs and the
616 internals of strings and string-like objects confined to this file.
617*/
618
619#define SYMBOL_STRINGBUF SCM_CELL_OBJECT_1
620
621SCM
6869328b
MV
622scm_i_make_symbol (SCM name, scm_t_bits flags,
623 unsigned long hash, SCM props)
3ee86942
MV
624{
625 SCM buf;
626 size_t start = STRING_START (name);
627 size_t length = STRING_LENGTH (name);
628
629 if (IS_SH_STRING (name))
630 {
631 name = SH_STRING_STRING (name);
632 start += STRING_START (name);
633 }
634 buf = SYMBOL_STRINGBUF (name);
635
636 if (start == 0 && length == STRINGBUF_LENGTH (buf))
637 {
638 /* reuse buf. */
9de87eea 639 scm_i_pthread_mutex_lock (&stringbuf_write_mutex);
3ee86942 640 SET_STRINGBUF_SHARED (buf);
9de87eea 641 scm_i_pthread_mutex_unlock (&stringbuf_write_mutex);
3ee86942
MV
642 }
643 else
644 {
645 /* make new buf. */
9c44cd45
MG
646 if (scm_i_is_narrow_string (name))
647 {
648 SCM new_buf = make_stringbuf (length);
649 memcpy (STRINGBUF_CHARS (new_buf),
650 STRINGBUF_CHARS (buf) + start, length);
651 buf = new_buf;
652 }
653 else
654 {
655 SCM new_buf = make_wide_stringbuf (length);
656 u32_cpy ((scm_t_uint32 *) STRINGBUF_WIDE_CHARS (new_buf),
657 (scm_t_uint32 *) STRINGBUF_WIDE_CHARS (buf) + start,
658 length);
659 buf = new_buf;
660 }
3ee86942 661 }
6869328b 662 return scm_double_cell (scm_tc7_symbol | flags, SCM_UNPACK (buf),
3ee86942
MV
663 (scm_t_bits) hash, SCM_UNPACK (props));
664}
665
fd0a5bbc
HWN
666SCM
667scm_i_c_make_symbol (const char *name, size_t len,
668 scm_t_bits flags, unsigned long hash, SCM props)
669{
670 SCM buf = make_stringbuf (len);
671 memcpy (STRINGBUF_CHARS (buf), name, len);
672
673 return scm_double_cell (scm_tc7_symbol | flags, SCM_UNPACK (buf),
674 (scm_t_bits) hash, SCM_UNPACK (props));
675}
676
677/* Return a new symbol that uses the LEN bytes pointed to by NAME as its
678 underlying storage. */
679SCM
680scm_i_c_take_symbol (char *name, size_t len,
681 scm_t_bits flags, unsigned long hash, SCM props)
682{
683 SCM buf = scm_i_take_stringbufn (name, len);
684
685 return scm_double_cell (scm_tc7_symbol | flags, SCM_UNPACK (buf),
686 (scm_t_bits) hash, SCM_UNPACK (props));
687}
688
50b1996f
MG
689/* Returns the number of characters in SYM. This may be different
690 from the memory size of SYM. */
3ee86942
MV
691size_t
692scm_i_symbol_length (SCM sym)
0f2d19dd 693{
3ee86942 694 return STRINGBUF_LENGTH (SYMBOL_STRINGBUF (sym));
0f2d19dd
JB
695}
696
071bb6a8
LC
697size_t
698scm_c_symbol_length (SCM sym)
699#define FUNC_NAME "scm_c_symbol_length"
700{
701 SCM_VALIDATE_SYMBOL (1, sym);
702
703 return STRINGBUF_LENGTH (SYMBOL_STRINGBUF (sym));
704}
705#undef FUNC_NAME
706
50b1996f
MG
707/* True if the name of SYM is stored as a Latin-1 encoded string.
708 False if it is stored as a 32-bit UCS-4-encoded string. */
9c44cd45
MG
709int
710scm_i_is_narrow_symbol (SCM sym)
711{
712 SCM buf;
713
714 buf = SYMBOL_STRINGBUF (sym);
715 return !STRINGBUF_WIDE (buf);
716}
717
50b1996f
MG
718/* Returns a pointer to the 8-bit Latin-1 encoded character array that
719 contains the name of SYM. */
3ee86942
MV
720const char *
721scm_i_symbol_chars (SCM sym)
722{
9c44cd45
MG
723 SCM buf;
724
725 buf = SYMBOL_STRINGBUF (sym);
726 if (!STRINGBUF_WIDE (buf))
f59cf998 727 return (const char *) STRINGBUF_CHARS (buf);
9c44cd45
MG
728 else
729 scm_misc_error (NULL, "Invalid access of chars of a wide symbol ~S",
730 scm_list_1 (sym));
731}
732
50b1996f
MG
733/* Return a pointer to the 32-bit UCS-4-encoded character array of a
734 symbol's name. */
9c44cd45
MG
735const scm_t_wchar *
736scm_i_symbol_wide_chars (SCM sym)
737{
738 SCM buf;
739
740 buf = SYMBOL_STRINGBUF (sym);
741 if (STRINGBUF_WIDE (buf))
f59cf998 742 return (const scm_t_wchar *) STRINGBUF_WIDE_CHARS (buf);
9c44cd45
MG
743 else
744 scm_misc_error (NULL, "Invalid access of chars of a narrow symbol ~S",
745 scm_list_1 (sym));
3ee86942 746}
1cc91f1b 747
3ee86942
MV
748SCM
749scm_i_symbol_mark (SCM sym)
0f2d19dd 750{
3ee86942
MV
751 scm_gc_mark (SYMBOL_STRINGBUF (sym));
752 return SCM_CELL_OBJECT_3 (sym);
0f2d19dd
JB
753}
754
3ee86942
MV
755void
756scm_i_symbol_free (SCM sym)
757{
758}
0f2d19dd 759
be54b15d 760SCM
3ee86942 761scm_i_symbol_substring (SCM sym, size_t start, size_t end)
be54b15d 762{
3ee86942 763 SCM buf = SYMBOL_STRINGBUF (sym);
9de87eea 764 scm_i_pthread_mutex_lock (&stringbuf_write_mutex);
3ee86942 765 SET_STRINGBUF_SHARED (buf);
9de87eea 766 scm_i_pthread_mutex_unlock (&stringbuf_write_mutex);
fd2b17b9 767 return scm_double_cell (RO_STRING_TAG, SCM_UNPACK (buf),
3ee86942
MV
768 (scm_t_bits)start, (scm_t_bits) end - start);
769}
be54b15d 770
50b1996f 771/* Returns the Xth character of symbol SYM as a UCS-4 codepoint. */
9c44cd45
MG
772scm_t_wchar
773scm_i_symbol_ref (SCM sym, size_t x)
774{
775 if (scm_i_is_narrow_symbol (sym))
776 return (scm_t_wchar) (unsigned char) (scm_i_symbol_chars (sym)[x]);
777 else
778 return scm_i_symbol_wide_chars (sym)[x];
779}
780
3ee86942
MV
781/* Debugging
782 */
be54b15d 783
6ce6923b
MG
784SCM_DEFINE (scm_sys_string_dump, "%string-dump", 1, 0, 0, (SCM str),
785 "Returns an association list containing debugging information\n"
786 "for @var{str}. The association list has the following entries."
787 "@table @code\n"
788 "@item string\n"
789 "The string itself.\n"
790 "@item start\n"
791 "The start index of the string into its stringbuf\n"
792 "@item length\n"
793 "The length of the string\n"
794 "@item shared\n"
795 "If this string is a substring, it returns its parent string.\n"
796 "Otherwise, it returns @code{#f}\n"
88ed5759
MG
797 "@item read-only\n"
798 "@code{#t} if the string is read-only\n"
6ce6923b
MG
799 "@item stringbuf-chars\n"
800 "A new string containing this string's stringbuf's characters\n"
801 "@item stringbuf-length\n"
802 "The number of characters in this stringbuf\n"
803 "@item stringbuf-shared\n"
804 "@code{#t} if this stringbuf is shared\n"
805 "@item stringbuf-inline\n"
806 "@code{#t} if this stringbuf's characters are stored in the\n"
807 "cell itself, or @code{#f} if they were allocated in memory\n"
808 "@item stringbuf-wide\n"
809 "@code{#t} if this stringbuf's characters are stored in a\n"
810 "32-bit buffer, or @code{#f} if they are stored in an 8-bit\n"
811 "buffer\n"
812 "@end table")
3ee86942
MV
813#define FUNC_NAME s_scm_sys_string_dump
814{
6ce6923b
MG
815 SCM e1, e2, e3, e4, e5, e6, e7, e8, e9, e10;
816 SCM buf;
3ee86942 817 SCM_VALIDATE_STRING (1, str);
6ce6923b
MG
818
819 /* String info */
820 e1 = scm_cons (scm_from_locale_symbol ("string"),
821 str);
822 e2 = scm_cons (scm_from_locale_symbol ("start"),
823 scm_from_size_t (STRING_START (str)));
824 e3 = scm_cons (scm_from_locale_symbol ("length"),
825 scm_from_size_t (STRING_LENGTH (str)));
826
3ee86942
MV
827 if (IS_SH_STRING (str))
828 {
6ce6923b
MG
829 e4 = scm_cons (scm_from_locale_symbol ("shared"),
830 SH_STRING_STRING (str));
831 buf = STRING_STRINGBUF (SH_STRING_STRING (str));
3ee86942
MV
832 }
833 else
834 {
6ce6923b
MG
835 e4 = scm_cons (scm_from_locale_symbol ("shared"),
836 SCM_BOOL_F);
837 buf = STRING_STRINGBUF (str);
838 }
9c44cd45 839
88ed5759
MG
840 if (IS_RO_STRING (str))
841 e5 = scm_cons (scm_from_locale_symbol ("read-only"),
842 SCM_BOOL_T);
843 else
844 e5 = scm_cons (scm_from_locale_symbol ("read-only"),
845 SCM_BOOL_F);
846
6ce6923b 847 /* Stringbuf info */
6ce6923b
MG
848 if (!STRINGBUF_WIDE (buf))
849 {
850 size_t len = STRINGBUF_LENGTH (buf);
851 char *cbuf;
852 SCM sbc = scm_i_make_string (len, &cbuf);
853 memcpy (cbuf, STRINGBUF_CHARS (buf), len);
854 e6 = scm_cons (scm_from_locale_symbol ("stringbuf-chars"),
855 sbc);
3ee86942 856 }
6ce6923b
MG
857 else
858 {
859 size_t len = STRINGBUF_LENGTH (buf);
860 scm_t_wchar *cbuf;
861 SCM sbc = scm_i_make_wide_string (len, &cbuf);
862 u32_cpy ((scm_t_uint32 *) cbuf,
863 (scm_t_uint32 *) STRINGBUF_WIDE_CHARS (buf), len);
864 e6 = scm_cons (scm_from_locale_symbol ("stringbuf-chars"),
865 sbc);
866 }
867 e7 = scm_cons (scm_from_locale_symbol ("stringbuf-length"),
868 scm_from_size_t (STRINGBUF_LENGTH (buf)));
869 if (STRINGBUF_SHARED (buf))
870 e8 = scm_cons (scm_from_locale_symbol ("stringbuf-shared"),
871 SCM_BOOL_T);
872 else
873 e8 = scm_cons (scm_from_locale_symbol ("stringbuf-shared"),
874 SCM_BOOL_F);
875 if (STRINGBUF_INLINE (buf))
876 e9 = scm_cons (scm_from_locale_symbol ("stringbuf-inline"),
877 SCM_BOOL_T);
878 else
879 e9 = scm_cons (scm_from_locale_symbol ("stringbuf-inline"),
880 SCM_BOOL_F);
881 if (STRINGBUF_WIDE (buf))
882 e10 = scm_cons (scm_from_locale_symbol ("stringbuf-wide"),
883 SCM_BOOL_T);
884 else
885 e10 = scm_cons (scm_from_locale_symbol ("stringbuf-wide"),
886 SCM_BOOL_F);
887
888 return scm_list_n (e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, SCM_UNDEFINED);
3ee86942
MV
889}
890#undef FUNC_NAME
891
6ce6923b
MG
892SCM_DEFINE (scm_sys_symbol_dump, "%symbol-dump", 1, 0, 0, (SCM sym),
893 "Returns an association list containing debugging information\n"
894 "for @var{sym}. The association list has the following entries."
895 "@table @code\n"
896 "@item symbol\n"
897 "The symbol itself\n"
898 "@item hash\n"
899 "Its hash value\n"
88ed5759
MG
900 "@item interned\n"
901 "@code{#t} if it is an interned symbol\n"
6ce6923b
MG
902 "@item stringbuf-chars\n"
903 "A new string containing this symbols's stringbuf's characters\n"
904 "@item stringbuf-length\n"
905 "The number of characters in this stringbuf\n"
906 "@item stringbuf-shared\n"
907 "@code{#t} if this stringbuf is shared\n"
908 "@item stringbuf-inline\n"
909 "@code{#t} if this stringbuf's characters are stored in the\n"
910 "cell itself, or @code{#f} if they were allocated in memory\n"
911 "@item stringbuf-wide\n"
912 "@code{#t} if this stringbuf's characters are stored in a\n"
913 "32-bit buffer, or @code{#f} if they are stored in an 8-bit\n"
914 "buffer\n"
915 "@end table")
3ee86942
MV
916#define FUNC_NAME s_scm_sys_symbol_dump
917{
6ce6923b
MG
918 SCM e1, e2, e3, e4, e5, e6, e7, e8;
919 SCM buf;
3ee86942 920 SCM_VALIDATE_SYMBOL (1, sym);
6ce6923b
MG
921 e1 = scm_cons (scm_from_locale_symbol ("symbol"),
922 sym);
923 e2 = scm_cons (scm_from_locale_symbol ("hash"),
924 scm_from_ulong (scm_i_symbol_hash (sym)));
88ed5759
MG
925 e3 = scm_cons (scm_from_locale_symbol ("interned"),
926 scm_symbol_interned_p (sym));
6ce6923b
MG
927 buf = SYMBOL_STRINGBUF (sym);
928
929 /* Stringbuf info */
6ce6923b
MG
930 if (!STRINGBUF_WIDE (buf))
931 {
932 size_t len = STRINGBUF_LENGTH (buf);
933 char *cbuf;
934 SCM sbc = scm_i_make_string (len, &cbuf);
935 memcpy (cbuf, STRINGBUF_CHARS (buf), len);
936 e4 = scm_cons (scm_from_locale_symbol ("stringbuf-chars"),
937 sbc);
938 }
9c44cd45 939 else
6ce6923b
MG
940 {
941 size_t len = STRINGBUF_LENGTH (buf);
942 scm_t_wchar *cbuf;
943 SCM sbc = scm_i_make_wide_string (len, &cbuf);
944 u32_cpy ((scm_t_uint32 *) cbuf,
945 (scm_t_uint32 *) STRINGBUF_WIDE_CHARS (buf), len);
946 e4 = scm_cons (scm_from_locale_symbol ("stringbuf-chars"),
947 sbc);
948 }
949 e5 = scm_cons (scm_from_locale_symbol ("stringbuf-length"),
950 scm_from_size_t (STRINGBUF_LENGTH (buf)));
951 if (STRINGBUF_SHARED (buf))
952 e6 = scm_cons (scm_from_locale_symbol ("stringbuf-shared"),
953 SCM_BOOL_T);
954 else
955 e6 = scm_cons (scm_from_locale_symbol ("stringbuf-shared"),
956 SCM_BOOL_F);
957 if (STRINGBUF_INLINE (buf))
958 e7 = scm_cons (scm_from_locale_symbol ("stringbuf-inline"),
959 SCM_BOOL_T);
960 else
961 e7 = scm_cons (scm_from_locale_symbol ("stringbuf-inline"),
962 SCM_BOOL_F);
963 if (STRINGBUF_WIDE (buf))
964 e8 = scm_cons (scm_from_locale_symbol ("stringbuf-wide"),
965 SCM_BOOL_T);
966 else
967 e8 = scm_cons (scm_from_locale_symbol ("stringbuf-wide"),
968 SCM_BOOL_F);
969 return scm_list_n (e1, e2, e3, e4, e5, e6, e7, e8, SCM_UNDEFINED);
970
3ee86942
MV
971}
972#undef FUNC_NAME
973
6ce6923b
MG
974#if SCM_STRING_LENGTH_HISTOGRAM
975
9c44cd45 976SCM_DEFINE (scm_sys_stringbuf_hist, "%stringbuf-hist", 0, 0, 0, (void), "")
e1b29f6a 977#define FUNC_NAME s_scm_sys_stringbuf_hist
3ee86942
MV
978{
979 int i;
980 for (i = 0; i < 1000; i++)
981 if (lenhist[i])
982 fprintf (stderr, " %3d: %u\n", i, lenhist[i]);
983 fprintf (stderr, ">999: %u\n", lenhist[1000]);
984 return SCM_UNSPECIFIED;
be54b15d
DH
985}
986#undef FUNC_NAME
987
3ee86942
MV
988#endif
989
990\f
991
992SCM_DEFINE (scm_string_p, "string?", 1, 0, 0,
993 (SCM obj),
994 "Return @code{#t} if @var{obj} is a string, else @code{#f}.")
995#define FUNC_NAME s_scm_string_p
996{
997 return scm_from_bool (IS_STRING (obj));
998}
999#undef FUNC_NAME
1000
1001
1002SCM_REGISTER_PROC (s_scm_list_to_string, "list->string", 1, 0, 0, scm_string);
1003
1004SCM_DEFINE (scm_string, "string", 0, 0, 1,
1005 (SCM chrs),
1006 "@deffnx {Scheme Procedure} list->string chrs\n"
1007 "Return a newly allocated string composed of the arguments,\n"
1008 "@var{chrs}.")
1009#define FUNC_NAME s_scm_string
1010{
9aa27c1a 1011 SCM result = SCM_BOOL_F;
9c44cd45 1012 SCM rest;
3ee86942 1013 size_t len;
9c44cd45
MG
1014 size_t p = 0;
1015 long i;
9aa27c1a 1016 int wide = 0;
3ee86942 1017
9c44cd45
MG
1018 /* Verify that this is a list of chars. */
1019 i = scm_ilength (chrs);
3c7cf7f5
MG
1020 SCM_ASSERT (i >= 0, chrs, SCM_ARG1, FUNC_NAME);
1021
9c44cd45
MG
1022 len = (size_t) i;
1023 rest = chrs;
3ee86942 1024
9c44cd45 1025 while (len > 0 && scm_is_pair (rest))
3ee86942 1026 {
9c44cd45 1027 SCM elt = SCM_CAR (rest);
3ee86942 1028 SCM_VALIDATE_CHAR (SCM_ARGn, elt);
9aa27c1a
MG
1029 if (SCM_CHAR (elt) > 0xFF)
1030 wide = 1;
9c44cd45
MG
1031 rest = SCM_CDR (rest);
1032 len--;
1033 scm_remember_upto_here_1 (elt);
1034 }
1035
1036 /* Construct a string containing this list of chars. */
1037 len = (size_t) i;
1038 rest = chrs;
1039
9aa27c1a 1040 if (wide == 0)
9c44cd45 1041 {
9aa27c1a
MG
1042 result = scm_i_make_string (len, NULL);
1043 result = scm_i_string_start_writing (result);
1044 char *buf = scm_i_string_writable_chars (result);
1045 while (len > 0 && scm_is_pair (rest))
1046 {
1047 SCM elt = SCM_CAR (rest);
1048 buf[p] = (unsigned char) SCM_CHAR (elt);
1049 p++;
1050 rest = SCM_CDR (rest);
1051 len--;
1052 scm_remember_upto_here_1 (elt);
1053 }
1054 }
1055 else
1056 {
1057 result = scm_i_make_wide_string (len, NULL);
1058 result = scm_i_string_start_writing (result);
1059 scm_t_wchar *buf = scm_i_string_writable_wide_chars (result);
1060 while (len > 0 && scm_is_pair (rest))
1061 {
1062 SCM elt = SCM_CAR (rest);
1063 buf[p] = SCM_CHAR (elt);
1064 p++;
1065 rest = SCM_CDR (rest);
1066 len--;
1067 scm_remember_upto_here_1 (elt);
1068 }
3ee86942 1069 }
9c44cd45
MG
1070 scm_i_string_stop_writing ();
1071
3ee86942
MV
1072 if (len > 0)
1073 scm_misc_error (NULL, "list changed while constructing string", SCM_EOL);
9c44cd45 1074 if (!scm_is_null (rest))
3ee86942
MV
1075 scm_wrong_type_arg_msg (NULL, 0, chrs, "proper list");
1076
1077 return result;
1078}
1079#undef FUNC_NAME
be54b15d 1080
3b3b36dd 1081SCM_DEFINE (scm_make_string, "make-string", 1, 1, 0,
6fa73e72 1082 (SCM k, SCM chr),
0d26a824
MG
1083 "Return a newly allocated string of\n"
1084 "length @var{k}. If @var{chr} is given, then all elements of\n"
1085 "the string are initialized to @var{chr}, otherwise the contents\n"
9401323e 1086 "of the @var{string} are unspecified.")
1bbd0b84 1087#define FUNC_NAME s_scm_make_string
0f2d19dd 1088{
3ee86942
MV
1089 return scm_c_make_string (scm_to_size_t (k), chr);
1090}
1091#undef FUNC_NAME
1092
1093SCM
1094scm_c_make_string (size_t len, SCM chr)
1095#define FUNC_NAME NULL
1096{
9c44cd45
MG
1097 size_t p;
1098 SCM res = scm_i_make_string (len, NULL);
cb0d8be2 1099
e11e83f3
MV
1100 if (!SCM_UNBNDP (chr))
1101 {
3ee86942 1102 SCM_VALIDATE_CHAR (0, chr);
9c44cd45
MG
1103 res = scm_i_string_start_writing (res);
1104 for (p = 0; p < len; p++)
1105 scm_i_string_set_x (res, p, SCM_CHAR (chr));
1106 scm_i_string_stop_writing ();
0f2d19dd 1107 }
e11e83f3
MV
1108
1109 return res;
0f2d19dd 1110}
1bbd0b84 1111#undef FUNC_NAME
0f2d19dd 1112
3b3b36dd 1113SCM_DEFINE (scm_string_length, "string-length", 1, 0, 0,
0d26a824
MG
1114 (SCM string),
1115 "Return the number of characters in @var{string}.")
1bbd0b84 1116#define FUNC_NAME s_scm_string_length
0f2d19dd 1117{
d1ca2c64 1118 SCM_VALIDATE_STRING (1, string);
3ee86942 1119 return scm_from_size_t (STRING_LENGTH (string));
0f2d19dd 1120}
1bbd0b84 1121#undef FUNC_NAME
0f2d19dd 1122
f8ba2bb9 1123SCM_DEFINE (scm_string_bytes_per_char, "string-bytes-per-char", 1, 0, 0,
9c44cd45
MG
1124 (SCM string),
1125 "Return the bytes used to represent a character in @var{string}."
1126 "This will return 1 or 4.")
f8ba2bb9 1127#define FUNC_NAME s_scm_string_bytes_per_char
9c44cd45
MG
1128{
1129 SCM_VALIDATE_STRING (1, string);
1130 if (!scm_i_is_narrow_string (string))
1131 return scm_from_int (4);
1132
1133 return scm_from_int (1);
1134}
1135#undef FUNC_NAME
1136
3ee86942
MV
1137size_t
1138scm_c_string_length (SCM string)
1139{
1140 if (!IS_STRING (string))
1141 scm_wrong_type_arg_msg (NULL, 0, string, "string");
1142 return STRING_LENGTH (string);
1143}
1144
bd9e24b3 1145SCM_DEFINE (scm_string_ref, "string-ref", 2, 0, 0,
6fa73e72 1146 (SCM str, SCM k),
9c44cd45
MG
1147 "Return character @var{k} of @var{str} using zero-origin\n"
1148 "indexing. @var{k} must be a valid index of @var{str}.")
1bbd0b84 1149#define FUNC_NAME s_scm_string_ref
0f2d19dd 1150{
3ae3166b 1151 size_t len;
a55c2b68 1152 unsigned long idx;
bd9e24b3 1153
d1ca2c64 1154 SCM_VALIDATE_STRING (1, str);
3ae3166b
LC
1155
1156 len = scm_i_string_length (str);
1157 if (SCM_LIKELY (len > 0))
1158 idx = scm_to_unsigned_integer (k, 0, len - 1);
1159 else
1160 scm_out_of_range (NULL, k);
1161
9c44cd45
MG
1162 if (scm_i_is_narrow_string (str))
1163 return SCM_MAKE_CHAR (scm_i_string_chars (str)[idx]);
1164 else
1165 return SCM_MAKE_CHAR (scm_i_string_wide_chars (str)[idx]);
0f2d19dd 1166}
1bbd0b84 1167#undef FUNC_NAME
0f2d19dd 1168
3ee86942
MV
1169SCM
1170scm_c_string_ref (SCM str, size_t p)
1171{
1172 if (p >= scm_i_string_length (str))
1173 scm_out_of_range (NULL, scm_from_size_t (p));
9c44cd45
MG
1174 if (scm_i_is_narrow_string (str))
1175 return SCM_MAKE_CHAR (scm_i_string_chars (str)[p]);
1176 else
1177 return SCM_MAKE_CHAR (scm_i_string_wide_chars (str)[p]);
1178
3ee86942 1179}
f0942910 1180
3b3b36dd 1181SCM_DEFINE (scm_string_set_x, "string-set!", 3, 0, 0,
6fa73e72 1182 (SCM str, SCM k, SCM chr),
9c44cd45
MG
1183 "Store @var{chr} in element @var{k} of @var{str} and return\n"
1184 "an unspecified value. @var{k} must be a valid index of\n"
1185 "@var{str}.")
1bbd0b84 1186#define FUNC_NAME s_scm_string_set_x
0f2d19dd 1187{
3ae3166b 1188 size_t len;
a55c2b68
MV
1189 unsigned long idx;
1190
f0942910 1191 SCM_VALIDATE_STRING (1, str);
3ae3166b
LC
1192
1193 len = scm_i_string_length (str);
1194 if (SCM_LIKELY (len > 0))
1195 idx = scm_to_unsigned_integer (k, 0, len - 1);
1196 else
1197 scm_out_of_range (NULL, k);
1198
34d19ef6 1199 SCM_VALIDATE_CHAR (3, chr);
9c44cd45
MG
1200 str = scm_i_string_start_writing (str);
1201 scm_i_string_set_x (str, idx, SCM_CHAR (chr));
1202 scm_i_string_stop_writing ();
1203
0f2d19dd
JB
1204 return SCM_UNSPECIFIED;
1205}
1bbd0b84 1206#undef FUNC_NAME
0f2d19dd 1207
3ee86942
MV
1208void
1209scm_c_string_set_x (SCM str, size_t p, SCM chr)
1210{
1211 if (p >= scm_i_string_length (str))
1212 scm_out_of_range (NULL, scm_from_size_t (p));
9c44cd45
MG
1213 str = scm_i_string_start_writing (str);
1214 scm_i_string_set_x (str, p, SCM_CHAR (chr));
1215 scm_i_string_stop_writing ();
3ee86942 1216}
0f2d19dd 1217
3b3b36dd 1218SCM_DEFINE (scm_substring, "substring", 2, 1, 0,
0d26a824
MG
1219 (SCM str, SCM start, SCM end),
1220 "Return a newly allocated string formed from the characters\n"
1221 "of @var{str} beginning with index @var{start} (inclusive) and\n"
1222 "ending with index @var{end} (exclusive).\n"
1223 "@var{str} must be a string, @var{start} and @var{end} must be\n"
1224 "exact integers satisfying:\n\n"
1225 "0 <= @var{start} <= @var{end} <= (string-length @var{str}).")
1bbd0b84 1226#define FUNC_NAME s_scm_substring
0f2d19dd 1227{
3ee86942 1228 size_t len, from, to;
685c0d71 1229
d1ca2c64 1230 SCM_VALIDATE_STRING (1, str);
3ee86942
MV
1231 len = scm_i_string_length (str);
1232 from = scm_to_unsigned_integer (start, 0, len);
a55c2b68 1233 if (SCM_UNBNDP (end))
3ee86942 1234 to = len;
a55c2b68 1235 else
3ee86942
MV
1236 to = scm_to_unsigned_integer (end, from, len);
1237 return scm_i_substring (str, from, to);
0f2d19dd 1238}
1bbd0b84 1239#undef FUNC_NAME
0f2d19dd 1240
ed35de72
MV
1241SCM_DEFINE (scm_substring_read_only, "substring/read-only", 2, 1, 0,
1242 (SCM str, SCM start, SCM end),
1243 "Return a newly allocated string formed from the characters\n"
1244 "of @var{str} beginning with index @var{start} (inclusive) and\n"
1245 "ending with index @var{end} (exclusive).\n"
1246 "@var{str} must be a string, @var{start} and @var{end} must be\n"
1247 "exact integers satisfying:\n"
1248 "\n"
1249 "0 <= @var{start} <= @var{end} <= (string-length @var{str}).\n"
1250 "\n"
1251 "The returned string is read-only.\n")
1252#define FUNC_NAME s_scm_substring_read_only
1253{
1254 size_t len, from, to;
1255
1256 SCM_VALIDATE_STRING (1, str);
1257 len = scm_i_string_length (str);
1258 from = scm_to_unsigned_integer (start, 0, len);
1259 if (SCM_UNBNDP (end))
1260 to = len;
1261 else
1262 to = scm_to_unsigned_integer (end, from, len);
1263 return scm_i_substring_read_only (str, from, to);
1264}
1265#undef FUNC_NAME
1266
3ee86942
MV
1267SCM_DEFINE (scm_substring_copy, "substring/copy", 2, 1, 0,
1268 (SCM str, SCM start, SCM end),
1269 "Return a newly allocated string formed from the characters\n"
1270 "of @var{str} beginning with index @var{start} (inclusive) and\n"
1271 "ending with index @var{end} (exclusive).\n"
1272 "@var{str} must be a string, @var{start} and @var{end} must be\n"
1273 "exact integers satisfying:\n\n"
1274 "0 <= @var{start} <= @var{end} <= (string-length @var{str}).")
1275#define FUNC_NAME s_scm_substring_copy
1276{
e1b29f6a
MV
1277 /* For the Scheme version, START is mandatory, but for the C
1278 version, it is optional. See scm_string_copy in srfi-13.c for a
1279 rationale.
1280 */
1281
1282 size_t from, to;
3ee86942
MV
1283
1284 SCM_VALIDATE_STRING (1, str);
e1b29f6a
MV
1285 scm_i_get_substring_spec (scm_i_string_length (str),
1286 start, &from, end, &to);
3ee86942
MV
1287 return scm_i_substring_copy (str, from, to);
1288}
1289#undef FUNC_NAME
1290
1291SCM_DEFINE (scm_substring_shared, "substring/shared", 2, 1, 0,
1292 (SCM str, SCM start, SCM end),
1293 "Return string that indirectly refers to the characters\n"
1294 "of @var{str} beginning with index @var{start} (inclusive) and\n"
1295 "ending with index @var{end} (exclusive).\n"
1296 "@var{str} must be a string, @var{start} and @var{end} must be\n"
1297 "exact integers satisfying:\n\n"
1298 "0 <= @var{start} <= @var{end} <= (string-length @var{str}).")
1299#define FUNC_NAME s_scm_substring_shared
1300{
1301 size_t len, from, to;
1302
1303 SCM_VALIDATE_STRING (1, str);
1304 len = scm_i_string_length (str);
1305 from = scm_to_unsigned_integer (start, 0, len);
1306 if (SCM_UNBNDP (end))
1307 to = len;
1308 else
1309 to = scm_to_unsigned_integer (end, from, len);
1310 return scm_i_substring_shared (str, from, to);
1311}
1312#undef FUNC_NAME
685c0d71 1313
3b3b36dd 1314SCM_DEFINE (scm_string_append, "string-append", 0, 0, 1,
6fa73e72 1315 (SCM args),
9c44cd45 1316 "Return a newly allocated string whose characters form the\n"
0d26a824 1317 "concatenation of the given strings, @var{args}.")
1bbd0b84 1318#define FUNC_NAME s_scm_string_append
0f2d19dd
JB
1319{
1320 SCM res;
9c44cd45
MG
1321 size_t len = 0;
1322 int wide = 0;
c829a427 1323 SCM l, s;
bd4911ef 1324 size_t i;
9909c395
MG
1325 union
1326 {
1327 char *narrow;
1328 scm_t_wchar *wide;
1329 } data;
af45e3b0
DH
1330
1331 SCM_VALIDATE_REST_ARGUMENT (args);
9c44cd45 1332 for (l = args; !scm_is_null (l); l = SCM_CDR (l))
c829a427
MV
1333 {
1334 s = SCM_CAR (l);
1335 SCM_VALIDATE_STRING (SCM_ARGn, s);
9c44cd45
MG
1336 len += scm_i_string_length (s);
1337 if (!scm_i_is_narrow_string (s))
1338 wide = 1;
c829a427 1339 }
9909c395 1340 data.narrow = NULL;
9c44cd45 1341 if (!wide)
9909c395 1342 res = scm_i_make_string (len, &data.narrow);
9c44cd45 1343 else
9909c395 1344 res = scm_i_make_wide_string (len, &data.wide);
9c44cd45
MG
1345
1346 for (l = args; !scm_is_null (l); l = SCM_CDR (l))
c829a427 1347 {
edea856c 1348 size_t len;
c829a427 1349 s = SCM_CAR (l);
3ee86942 1350 SCM_VALIDATE_STRING (SCM_ARGn, s);
edea856c 1351 len = scm_i_string_length (s);
9c44cd45
MG
1352 if (!wide)
1353 {
9909c395
MG
1354 memcpy (data.narrow, scm_i_string_chars (s), len);
1355 data.narrow += len;
9c44cd45
MG
1356 }
1357 else
1358 {
1359 if (scm_i_is_narrow_string (s))
1360 {
1361 for (i = 0; i < scm_i_string_length (s); i++)
9909c395 1362 data.wide[i] = (unsigned char) scm_i_string_chars (s)[i];
9c44cd45
MG
1363 }
1364 else
9909c395 1365 u32_cpy ((scm_t_uint32 *) data.wide,
9c44cd45 1366 (scm_t_uint32 *) scm_i_string_wide_chars (s), len);
9909c395 1367 data.wide += len;
9c44cd45 1368 }
c829a427
MV
1369 scm_remember_upto_here_1 (s);
1370 }
0f2d19dd
JB
1371 return res;
1372}
1bbd0b84 1373#undef FUNC_NAME
0f2d19dd 1374
c829a427
MV
1375int
1376scm_is_string (SCM obj)
1377{
3ee86942 1378 return IS_STRING (obj);
c829a427 1379}
24933780 1380
c829a427
MV
1381SCM
1382scm_from_locale_stringn (const char *str, size_t len)
1383{
1384 SCM res;
1385 char *dst;
4d4528e7 1386
9c44cd45 1387 if (len == (size_t) -1)
c829a427 1388 len = strlen (str);
9c44cd45
MG
1389 if (len == 0)
1390 return scm_nullstr;
1391
3ee86942 1392 res = scm_i_make_string (len, &dst);
c829a427
MV
1393 memcpy (dst, str, len);
1394 return res;
1395}
4d4528e7 1396
c829a427
MV
1397SCM
1398scm_from_locale_string (const char *str)
4d4528e7 1399{
9c44cd45
MG
1400 if (str == NULL)
1401 return scm_nullstr;
1402
c829a427
MV
1403 return scm_from_locale_stringn (str, -1);
1404}
4d4528e7 1405
50b1996f
MG
1406/* Create a new scheme string from the C string STR. The memory of
1407 STR may be used directly as storage for the new string. */
c829a427
MV
1408SCM
1409scm_take_locale_stringn (char *str, size_t len)
1410{
48ddf0d9
KR
1411 SCM buf, res;
1412
9c44cd45 1413 if (len == (size_t) -1)
48ddf0d9 1414 len = strlen (str);
c829a427
MV
1415 else
1416 {
48ddf0d9
KR
1417 /* Ensure STR is null terminated. A realloc for 1 extra byte should
1418 often be satisfied from the alignment padding after the block, with
1419 no actual data movement. */
9c44cd45 1420 str = scm_realloc (str, len + 1);
48ddf0d9 1421 str[len] = '\0';
c829a427 1422 }
c829a427 1423
fd0a5bbc 1424 buf = scm_i_take_stringbufn (str, len);
3ee86942 1425 res = scm_double_cell (STRING_TAG,
9c44cd45 1426 SCM_UNPACK (buf), (scm_t_bits) 0, (scm_t_bits) len);
c829a427
MV
1427 return res;
1428}
1429
48ddf0d9
KR
1430SCM
1431scm_take_locale_string (char *str)
1432{
1433 return scm_take_locale_stringn (str, -1);
1434}
1435
9c44cd45
MG
1436/* Change libunistring escapes (\uXXXX and \UXXXXXXXX) to \xXX \uXXXX
1437 and \UXXXXXX. */
1438static void
1439unistring_escapes_to_guile_escapes (char **bufp, size_t *lenp)
1440{
1441 char *before, *after;
1442 size_t i, j;
1443
1444 before = *bufp;
1445 after = *bufp;
1446 i = 0;
1447 j = 0;
1448 while (i < *lenp)
1449 {
1450 if ((i <= *lenp - 6)
1451 && before[i] == '\\'
1452 && before[i + 1] == 'u'
1453 && before[i + 2] == '0' && before[i + 3] == '0')
1454 {
1455 /* Convert \u00NN to \xNN */
1456 after[j] = '\\';
1457 after[j + 1] = 'x';
30a6b9ca
MG
1458 after[j + 2] = tolower ((int) before[i + 4]);
1459 after[j + 3] = tolower ((int) before[i + 5]);
9c44cd45
MG
1460 i += 6;
1461 j += 4;
1462 }
1463 else if ((i <= *lenp - 10)
1464 && before[i] == '\\'
1465 && before[i + 1] == 'U'
1466 && before[i + 2] == '0' && before[i + 3] == '0')
1467 {
1468 /* Convert \U00NNNNNN to \UNNNNNN */
1469 after[j] = '\\';
1470 after[j + 1] = 'U';
30a6b9ca
MG
1471 after[j + 2] = tolower ((int) before[i + 4]);
1472 after[j + 3] = tolower ((int) before[i + 5]);
1473 after[j + 4] = tolower ((int) before[i + 6]);
1474 after[j + 5] = tolower ((int) before[i + 7]);
1475 after[j + 6] = tolower ((int) before[i + 8]);
1476 after[j + 7] = tolower ((int) before[i + 9]);
9c44cd45
MG
1477 i += 10;
1478 j += 8;
1479 }
1480 else
1481 {
1482 after[j] = before[i];
1483 i++;
1484 j++;
1485 }
1486 }
1487 *lenp = j;
1488 after = scm_realloc (after, j);
1489}
1490
c829a427 1491char *
9c44cd45 1492scm_to_locale_stringn (SCM str, size_t * lenp)
c829a427 1493{
9c44cd45
MG
1494 const char *enc;
1495
1496 /* In the future, enc will hold the port's encoding. */
1497 enc = NULL;
1498
eca29b02
MG
1499 return scm_to_stringn (str, lenp, enc,
1500 SCM_FAILED_CONVERSION_ESCAPE_SEQUENCE);
9c44cd45
MG
1501}
1502
1503/* Low-level scheme to C string conversion function. */
1504char *
1505scm_to_stringn (SCM str, size_t * lenp, const char *encoding,
eca29b02 1506 scm_t_string_failed_conversion_handler handler)
9c44cd45
MG
1507{
1508 static const char iso[11] = "ISO-8859-1";
1509 char *buf;
1510 size_t ilen, len, i;
4d4528e7 1511
3ee86942 1512 if (!scm_is_string (str))
c829a427 1513 scm_wrong_type_arg_msg (NULL, 0, str, "string");
9c44cd45
MG
1514 ilen = scm_i_string_length (str);
1515
1516 if (ilen == 0)
1517 {
1518 buf = scm_malloc (1);
1519 buf[0] = '\0';
1520 if (lenp)
1521 *lenp = 0;
1522 return buf;
1523 }
1524
c829a427 1525 if (lenp == NULL)
9c44cd45
MG
1526 for (i = 0; i < ilen; i++)
1527 if (scm_i_string_ref (str, i) == '\0')
1528 scm_misc_error (NULL,
1529 "string contains #\\nul character: ~S",
1530 scm_list_1 (str));
1531
1532 if (scm_i_is_narrow_string (str))
c829a427 1533 {
9c44cd45
MG
1534 if (lenp)
1535 {
1536 buf = scm_malloc (ilen);
1537 memcpy (buf, scm_i_string_chars (str), ilen);
1538 *lenp = ilen;
1539 return buf;
1540 }
1541 else
1542 {
1543 buf = scm_malloc (ilen + 1);
1544 memcpy (buf, scm_i_string_chars (str), ilen);
1545 buf[ilen] = '\0';
1546 return buf;
1547 }
c829a427 1548 }
9c44cd45
MG
1549
1550
1551 buf = NULL;
1552 len = 0;
1553 buf = u32_conv_to_encoding (iso,
eca29b02 1554 (enum iconv_ilseq_handler) handler,
9c44cd45
MG
1555 (scm_t_uint32 *) scm_i_string_wide_chars (str),
1556 ilen, NULL, NULL, &len);
1557 if (buf == NULL)
1558 scm_misc_error (NULL, "cannot convert to output locale ~s: \"~s\"",
1559 scm_list_2 (scm_from_locale_string (iso), str));
1560
eca29b02 1561 if (handler == SCM_FAILED_CONVERSION_ESCAPE_SEQUENCE)
9c44cd45
MG
1562 unistring_escapes_to_guile_escapes (&buf, &len);
1563
1564 if (lenp)
4d4528e7 1565 *lenp = len;
9c44cd45
MG
1566 else
1567 {
1568 buf = scm_realloc (buf, len + 1);
1569 buf[len] = '\0';
1570 }
24933780 1571
c829a427 1572 scm_remember_upto_here_1 (str);
9c44cd45 1573 return buf;
4d4528e7 1574}
af68e5e5 1575
c829a427
MV
1576char *
1577scm_to_locale_string (SCM str)
1578{
1579 return scm_to_locale_stringn (str, NULL);
1580}
af68e5e5 1581
c829a427
MV
1582size_t
1583scm_to_locale_stringbuf (SCM str, char *buf, size_t max_len)
1584{
1585 size_t len;
9c44cd45 1586 char *result = NULL;
3ee86942 1587 if (!scm_is_string (str))
c829a427 1588 scm_wrong_type_arg_msg (NULL, 0, str, "string");
9c44cd45
MG
1589 result = scm_to_locale_stringn (str, &len);
1590
1591 memcpy (buf, result, (len > max_len) ? max_len : len);
1592 free (result);
1593
c829a427
MV
1594 scm_remember_upto_here_1 (str);
1595 return len;
1596}
af68e5e5 1597
3ee86942
MV
1598/* converts C scm_array of strings to SCM scm_list of strings. */
1599/* If argc < 0, a null terminated scm_array is assumed. */
9c44cd45 1600SCM
3ee86942
MV
1601scm_makfromstrs (int argc, char **argv)
1602{
1603 int i = argc;
1604 SCM lst = SCM_EOL;
1605 if (0 > i)
1606 for (i = 0; argv[i]; i++);
1607 while (i--)
1608 lst = scm_cons (scm_from_locale_string (argv[i]), lst);
1609 return lst;
1610}
1611
c829a427
MV
1612/* Return a newly allocated array of char pointers to each of the strings
1613 in args, with a terminating NULL pointer. */
1614
1615char **
1616scm_i_allocate_string_pointers (SCM list)
af68e5e5 1617{
c829a427
MV
1618 char **result;
1619 int len = scm_ilength (list);
1620 int i;
1621
1622 if (len < 0)
1623 scm_wrong_type_arg_msg (NULL, 0, list, "proper list");
1624
661ae7ab 1625 scm_dynwind_begin (0);
c829a427
MV
1626
1627 result = (char **) scm_malloc ((len + 1) * sizeof (char *));
1628 result[len] = NULL;
661ae7ab 1629 scm_dynwind_unwind_handler (free, result, 0);
c829a427
MV
1630
1631 /* The list might be have been modified in another thread, so
1632 we check LIST before each access.
1633 */
d2e53ed6 1634 for (i = 0; i < len && scm_is_pair (list); i++)
c829a427
MV
1635 {
1636 result[i] = scm_to_locale_string (SCM_CAR (list));
1637 list = SCM_CDR (list);
1638 }
1639
661ae7ab 1640 scm_dynwind_end ();
c829a427 1641 return result;
af68e5e5 1642}
e53cc817 1643
c829a427
MV
1644void
1645scm_i_free_string_pointers (char **pointers)
1646{
1647 int i;
1648
1649 for (i = 0; pointers[i]; i++)
1650 free (pointers[i]);
1651 free (pointers);
1652}
24933780 1653
6f14f578
MV
1654void
1655scm_i_get_substring_spec (size_t len,
1656 SCM start, size_t *cstart,
1657 SCM end, size_t *cend)
1658{
1659 if (SCM_UNBNDP (start))
1660 *cstart = 0;
1661 else
1662 *cstart = scm_to_unsigned_integer (start, 0, len);
1663
1664 if (SCM_UNBNDP (end))
1665 *cend = len;
1666 else
1667 *cend = scm_to_unsigned_integer (end, *cstart, len);
1668}
1669
3ee86942
MV
1670#if SCM_ENABLE_DEPRECATED
1671
556d75db
MV
1672/* When these definitions are removed, it becomes reasonable to use
1673 read-only strings for string literals. For that, change the reader
1674 to create string literals with scm_c_substring_read_only instead of
1675 with scm_c_substring_copy.
1676*/
1677
3ee86942 1678int
fe78c51a 1679scm_i_deprecated_stringp (SCM str)
3ee86942
MV
1680{
1681 scm_c_issue_deprecation_warning
1682 ("SCM_STRINGP is deprecated. Use scm_is_string instead.");
1683
2616f0e0 1684 return scm_is_string (str);
3ee86942
MV
1685}
1686
1687char *
fe78c51a 1688scm_i_deprecated_string_chars (SCM str)
3ee86942
MV
1689{
1690 char *chars;
1691
1692 scm_c_issue_deprecation_warning
1693 ("SCM_STRING_CHARS is deprecated. See the manual for alternatives.");
1694
2616f0e0
MV
1695 /* We don't accept shared substrings here since they are not
1696 null-terminated.
1697 */
1698 if (IS_SH_STRING (str))
1699 scm_misc_error (NULL,
1700 "SCM_STRING_CHARS does not work with shared substrings.",
1701 SCM_EOL);
1702
877f06c3 1703 /* We explicitly test for read-only strings to produce a better
556d75db
MV
1704 error message.
1705 */
1706
1707 if (IS_RO_STRING (str))
1708 scm_misc_error (NULL,
1709 "SCM_STRING_CHARS does not work with read-only strings.",
1710 SCM_EOL);
1711
2616f0e0 1712 /* The following is still wrong, of course...
3ee86942 1713 */
9c44cd45 1714 str = scm_i_string_start_writing (str);
3ee86942
MV
1715 chars = scm_i_string_writable_chars (str);
1716 scm_i_string_stop_writing ();
1717 return chars;
1718}
1719
1720size_t
fe78c51a 1721scm_i_deprecated_string_length (SCM str)
3ee86942
MV
1722{
1723 scm_c_issue_deprecation_warning
1724 ("SCM_STRING_LENGTH is deprecated. Use scm_c_string_length instead.");
1725 return scm_c_string_length (str);
1726}
1727
1728#endif
1729
0f2d19dd
JB
1730void
1731scm_init_strings ()
0f2d19dd 1732{
3ee86942 1733 scm_nullstr = scm_i_make_string (0, NULL);
7c33806a 1734
a0599745 1735#include "libguile/strings.x"
0f2d19dd
JB
1736}
1737
89e00824
ML
1738
1739/*
1740 Local Variables:
1741 c-file-style: "gnu"
1742 End:
1743*/