~peter-pearse/ubuntu/natty/guile-1.8/prop001

« back to all changes in this revision

Viewing changes to libguile/strings.c

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Schepler
  • Date: 2006-11-09 03:11:16 UTC
  • Revision ID: james.westby@ubuntu.com-20061109031116-hu0q1jxqg12y6yeg
Tags: upstream-1.8.1+1
ImportĀ upstreamĀ versionĀ 1.8.1+1

Show diffs side-by-side

added added

removed removed

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