~ubuntu-branches/ubuntu/hardy/uim/hardy

« back to all changes in this revision

Viewing changes to sigscheme/src/write.c

  • Committer: Bazaar Package Importer
  • Author(s): Masahito Omote
  • Date: 2007-04-21 03:46:09 UTC
  • mfrom: (1.1.6 upstream)
  • Revision ID: james.westby@ubuntu.com-20070421034609-gpcurkutp8vaysqj
Tags: 1:1.4.1-3
* Switch to dh_gtkmodules for the gtk 2.10 transition (Closes:
  #419318)
  - debian/control: Add ${misc:Depends} and remove libgtk2.0-bin on
    uim-gtk2.0.
  - debian/uim-gtk2.0.post{inst,rm}: Removed.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*===========================================================================
 
2
 *  Filename : write.c
 
3
 *  About    : Object writer
 
4
 *
 
5
 *  Copyright (C) 2005      Kazuki Ohta <mover AT hct.zaq.ne.jp>
 
6
 *  Copyright (C) 2005-2006 Jun Inoue <jun.lambda AT gmail.com>
 
7
 *  Copyright (C) 2005-2006 YAMAMOTO Kengo <yamaken AT bp.iij4u.or.jp>
 
8
 *  Copyright (c) 2007 SigScheme Project <uim AT freedesktop.org>
 
9
 *
 
10
 *  All rights reserved.
 
11
 *
 
12
 *  Redistribution and use in source and binary forms, with or without
 
13
 *  modification, are permitted provided that the following conditions
 
14
 *  are met:
 
15
 *
 
16
 *  1. Redistributions of source code must retain the above copyright
 
17
 *     notice, this list of conditions and the following disclaimer.
 
18
 *  2. Redistributions in binary form must reproduce the above copyright
 
19
 *     notice, this list of conditions and the following disclaimer in the
 
20
 *     documentation and/or other materials provided with the distribution.
 
21
 *  3. Neither the name of authors nor the names of its contributors
 
22
 *     may be used to endorse or promote products derived from this software
 
23
 *     without specific prior written permission.
 
24
 *
 
25
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
 
26
 *  IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 
27
 *  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 
28
 *  PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
 
29
 *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 
30
 *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 
31
 *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 
32
 *  OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 
33
 *  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 
34
 *  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 
35
 *  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
36
===========================================================================*/
 
37
 
 
38
/* TODO: make format.c independent */
 
39
 
 
40
#include <config.h>
 
41
 
 
42
#include <stdlib.h>
 
43
#include <stdio.h>
 
44
#include <stdarg.h>
 
45
#include <string.h>
 
46
 
 
47
#include "sigscheme.h"
 
48
#include "sigschemeinternal.h"
 
49
 
 
50
/*=======================================
 
51
  File Local Macro Definitions
 
52
=======================================*/
 
53
#if SCM_USE_SRFI38
 
54
#if !SCM_USE_STRING
 
55
#define STRINGP(o)        0
 
56
#define SCM_STRING_LEN(o) 0
 
57
#endif
 
58
#if !SCM_USE_VECTOR
 
59
#undef  VECTORP
 
60
#define VECTORP(o) 0
 
61
#endif
 
62
#define INTERESTINGP(obj)                                                    \
 
63
    (CONSP(obj)                                                              \
 
64
     || (STRINGP(obj) && SCM_STRING_LEN(obj))                                \
 
65
     || CLOSUREP(obj)                                                        \
 
66
     || VECTORP(obj)                                                         \
 
67
     || VALUEPACKETP(obj)                                                    \
 
68
     || ERROBJP(obj))
 
69
#define OCCUPIED(ent)      (!EQ((ent)->key, SCM_INVALID))
 
70
#define HASH_EMPTY(table)  (!(table).used)
 
71
/* datum index */
 
72
#define DEFINING_DATUM     (-1)
 
73
#define NONDEFINING_DATUM  0
 
74
/* flags */
 
75
#define HASH_INSERT    1 /* insert key if it's not registered yet */
 
76
#define HASH_FIND      0
 
77
#endif /* SCM_USE_SRFI38 */
 
78
 
 
79
/*=======================================
 
80
  File Local Type Definitions
 
81
=======================================*/
 
82
enum OutputType {
 
83
    UNKNOWN,
 
84
    AS_WRITE,  /* string is enclosed by ", char is written using #\ notation */
 
85
    AS_DISPLAY /* string and char is written as-is */
 
86
};
 
87
 
 
88
#if SCM_USE_SRFI38
 
89
typedef size_t hashval_t;
 
90
 
 
91
typedef struct {
 
92
    ScmObj key;
 
93
    scm_intobj_t datum;
 
94
} hash_entry;
 
95
 
 
96
typedef struct {
 
97
    size_t size;  /* capacity; MUST be a power of 2 */
 
98
    size_t used;  /* population */
 
99
    hash_entry *ents;
 
100
} hash_table;
 
101
 
 
102
typedef struct {
 
103
    hash_table seen; /* a table of seen objects */
 
104
    scm_intobj_t next_index;  /* the next index to use for #N# */
 
105
} write_ss_context;
 
106
#endif /* SCM_USE_SRFI38 */
 
107
 
 
108
/*=======================================
 
109
  Variable Definitions
 
110
=======================================*/
 
111
#include "functable-r5rs-write.c"
 
112
 
 
113
SCM_DEFINE_EXPORTED_VARS(write);
 
114
 
 
115
#if SCM_USE_SRFI38
 
116
SCM_GLOBAL_VARS_BEGIN(static_write);
 
117
#define static
 
118
/* misc info in priting shared structures */
 
119
static write_ss_context *l_write_ss_ctx;
 
120
#undef static
 
121
SCM_GLOBAL_VARS_END(static_write);
 
122
#define l_write_ss_ctx SCM_GLOBAL_VAR(static_write, l_write_ss_ctx)
 
123
SCM_DEFINE_STATIC_VARS(static_write);
 
124
#endif /* SCM_USE_SRFI38 */
 
125
 
 
126
/*=======================================
 
127
  File Local Function Declarations
 
128
=======================================*/
 
129
static void write_internal (ScmObj port, ScmObj obj, enum OutputType otype);
 
130
static void write_obj      (ScmObj port, ScmObj obj, enum OutputType otype);
 
131
#if SCM_USE_CHAR
 
132
static void write_char     (ScmObj port, ScmObj obj, enum OutputType otype);
 
133
#endif
 
134
#if SCM_USE_STRING
 
135
static void write_string   (ScmObj port, ScmObj obj, enum OutputType otype);
 
136
#endif
 
137
static void write_list     (ScmObj port, ScmObj lst, enum OutputType otype);
 
138
#if SCM_USE_VECTOR
 
139
static void write_vector   (ScmObj port, ScmObj vec, enum OutputType otype);
 
140
#endif
 
141
static void write_port     (ScmObj port, ScmObj obj, enum OutputType otype);
 
142
static void write_constant (ScmObj port, ScmObj obj, enum OutputType otype);
 
143
static void write_errobj   (ScmObj port, ScmObj obj, enum OutputType otype);
 
144
 
 
145
#if SCM_USE_HYGIENIC_MACRO
 
146
static void write_farsymbol(ScmObj port, ScmObj obj, enum OutputType otype);
 
147
#endif
 
148
 
 
149
#if SCM_USE_SRFI38
 
150
static void hash_grow(hash_table *tab);
 
151
static hash_entry *hash_lookup(hash_table *tab,
 
152
                               ScmObj key, scm_intobj_t datum, int flag);
 
153
static void write_ss_scan(ScmObj obj, write_ss_context *ctx);
 
154
static scm_intobj_t get_shared_index(ScmObj obj);
 
155
static void write_ss_internal(ScmObj port, ScmObj obj, enum OutputType otype);
 
156
#endif /* SCM_USE_SRFI38 */
 
157
 
 
158
/*=======================================
 
159
   Function Definitions
 
160
=======================================*/
 
161
SCM_EXPORT void
 
162
scm_init_writer(void)
 
163
{
 
164
    SCM_GLOBAL_VARS_INIT(write);
 
165
#if SCM_USE_SRFI38
 
166
    SCM_GLOBAL_VARS_INIT(static_write);
 
167
#endif
 
168
 
 
169
    scm_register_funcs(scm_functable_r5rs_write);
 
170
 
 
171
    /* To allow re-initialization of the interpreter, this variable must be
 
172
     * re-initialized by assignment. Initialized .data section does not work
 
173
     * for such situation.  -- YamaKen 2006-03-31 */
 
174
    scm_write_ss_func = scm_write;
 
175
}
 
176
 
 
177
SCM_EXPORT void
 
178
scm_write(ScmObj port, ScmObj obj)
 
179
{
 
180
    write_internal(port, obj, AS_WRITE);
 
181
}
 
182
 
 
183
SCM_EXPORT void
 
184
scm_display(ScmObj port, ScmObj obj)
 
185
{
 
186
    write_internal(port, obj, AS_DISPLAY);
 
187
}
 
188
 
 
189
static void
 
190
write_internal(ScmObj port, ScmObj obj, enum OutputType otype)
 
191
{
 
192
    DECLARE_INTERNAL_FUNCTION("write");
 
193
 
 
194
    ENSURE_PORT(port);
 
195
    SCM_ENSURE_LIVE_PORT(port);
 
196
    if (!(SCM_PORT_FLAG(port) & SCM_PORTFLAG_OUTPUT))
 
197
        ERR_OBJ("output port required but got", port);
 
198
 
 
199
    write_obj(port, obj, otype);
 
200
    scm_port_flush(port);
 
201
}
 
202
 
 
203
static void
 
204
write_obj(ScmObj port, ScmObj obj, enum OutputType otype)
 
205
{
 
206
    ScmObj sym;
 
207
 
 
208
#if SCM_USE_SRFI38
 
209
    if (INTERESTINGP(obj)) {
 
210
        scm_intobj_t index = get_shared_index(obj);
 
211
        if (index > 0) {
 
212
            /* defined datum */
 
213
            scm_format(port, SCM_FMT_RAW_C, "#~ZU#", (size_t)index);
 
214
            return;
 
215
        }
 
216
        if (index < 0) {
 
217
            /* defining datum, with the new index negated */
 
218
            scm_format(port, SCM_FMT_RAW_C, "#~ZU=", (size_t)-index);
 
219
            /* Print it; the next time it'll be defined. */
 
220
        }
 
221
    }
 
222
#endif
 
223
    switch (SCM_TYPE(obj)) {
 
224
#if SCM_USE_INT
 
225
    case ScmInt:
 
226
        scm_format(port, SCM_FMT_RAW_C, "~MD", SCM_INT_VALUE(obj));
 
227
        break;
 
228
#endif
 
229
    case ScmCons:
 
230
        if (ERROBJP(obj))
 
231
            write_errobj(port, obj, otype);
 
232
        else
 
233
            write_list(port, obj, otype);
 
234
        break;
 
235
    case ScmSymbol:
 
236
        scm_port_puts(port, SCM_SYMBOL_NAME(obj));
 
237
        break;
 
238
#if SCM_USE_CHAR
 
239
    case ScmChar:
 
240
        write_char(port, obj, otype);
 
241
        break;
 
242
#endif
 
243
#if SCM_USE_STRING
 
244
    case ScmString:
 
245
        write_string(port, obj, otype);
 
246
        break;
 
247
#endif
 
248
    case ScmFunc:
 
249
        scm_port_puts(port, (SCM_SYNTAXP(obj)) ? "#<syntax " : "#<subr ");
 
250
        sym = scm_symbol_bound_to(obj);
 
251
        if (TRUEP(sym))
 
252
            scm_display(port, sym);
 
253
        else
 
254
            scm_format(port, SCM_FMT_RAW_C, "~P", (void *)obj);
 
255
        scm_port_put_char(port, '>');
 
256
        break;
 
257
#if SCM_USE_HYGIENIC_MACRO
 
258
    case ScmMacro:
 
259
        scm_port_puts(port, "#<macro ");
 
260
        write_obj(port, SCM_HMACRO_RULES(obj), otype);
 
261
        scm_port_puts(port, ">");
 
262
        break;
 
263
    case ScmFarsymbol:
 
264
        write_farsymbol(port, obj, otype);
 
265
        break;
 
266
    case ScmSubpat:
 
267
        if (SCM_SUBPAT_PVARP(obj)) {
 
268
#if SCM_DEBUG_MACRO
 
269
            scm_port_puts(port, "#<pvar ");
 
270
            write_obj(port, SCM_SUBPAT_OBJ(obj), otype);
 
271
            scm_format(port, SCM_FMT_RAW_C, " ~MD>",
 
272
                       SCM_SUBPAT_PVAR_INDEX(obj));
 
273
#else  /* not SCM_DEBUG_MACRO */
 
274
            write_obj(port, SCM_SUBPAT_OBJ(obj), otype);
 
275
#endif /* not SCM_DEBUG_MACRO */
 
276
        } else {
 
277
            SCM_ASSERT(SCM_SUBPAT_REPPATP(obj));
 
278
            write_obj(port, SCM_SUBPAT_REPPAT_PAT(obj), otype);
 
279
#if SCM_DEBUG_MACRO
 
280
            scm_format(port, SCM_FMT_RAW_C, " ..[~MD]..",
 
281
                       SCM_SUBPAT_REPPAT_PVCOUNT(obj));
 
282
#else
 
283
            scm_port_puts(port, " ...");
 
284
#endif
 
285
        }
 
286
        break;
 
287
#endif /* SCM_USE_HYGIENIC_MACRO */
 
288
    case ScmClosure:
 
289
        scm_port_puts(port, "#<closure ");
 
290
        write_obj(port, SCM_CLOSURE_EXP(obj), otype);
 
291
        scm_port_put_char(port, '>');
 
292
        break;
 
293
#if SCM_USE_VECTOR
 
294
    case ScmVector:
 
295
        write_vector(port, obj, otype);
 
296
        break;
 
297
#endif
 
298
    case ScmPort:
 
299
        write_port(port, obj, otype);
 
300
        break;
 
301
#if SCM_USE_CONTINUATION
 
302
    case ScmContinuation:
 
303
        scm_format(port, SCM_FMT_RAW_C, "#<continuation ~P>", (void *)obj);
 
304
        break;
 
305
#endif
 
306
    case ScmValuePacket:
 
307
        scm_port_puts(port, "#<values ");
 
308
        write_obj(port, SCM_VALUEPACKET_VALUES(obj), otype);
 
309
#if SCM_USE_VALUECONS
 
310
#if SCM_USE_STORAGE_FATTY
 
311
        /* SCM_VALUEPACKET_VALUES() changes the type destructively */
 
312
        SCM_ENTYPE(obj, ScmValuePacket);
 
313
#else /* SCM_USE_STORAGE_FATTY */
 
314
#error "valuecons is not supported on this storage implementation"
 
315
#endif /* SCM_USE_STORAGE_FATTY */
 
316
#endif /* SCM_USE_VALUECONS */
 
317
        scm_port_put_char(port, '>');
 
318
        break;
 
319
    case ScmConstant:
 
320
        write_constant(port, obj, otype);
 
321
        break;
 
322
#if SCM_USE_SSCM_EXTENSIONS
 
323
    case ScmCPointer:
 
324
        scm_format(port, SCM_FMT_RAW_C,
 
325
                   "#<c_pointer ~P>", SCM_C_POINTER_VALUE(obj));
 
326
        break;
 
327
    case ScmCFuncPointer:
 
328
        scm_format(port, SCM_FMT_RAW_C,
 
329
                   "#<c_func_pointer ~P>",
 
330
                   (void *)(uintptr_t)SCM_C_FUNCPOINTER_VALUE(obj));
 
331
        break;
 
332
#endif
 
333
 
 
334
    case ScmRational:
 
335
    case ScmReal:
 
336
    case ScmComplex:
 
337
    default:
 
338
        SCM_NOTREACHED;
 
339
    }
 
340
}
 
341
 
 
342
#if SCM_USE_CHAR
 
343
static void
 
344
write_char(ScmObj port, ScmObj obj, enum OutputType otype)
 
345
{
 
346
    const ScmSpecialCharInfo *info;
 
347
    scm_ichar_t c;
 
348
 
 
349
    c = SCM_CHAR_VALUE(obj);
 
350
    switch (otype) {
 
351
    case AS_WRITE:
 
352
        scm_port_puts(port, "#\\");
 
353
        /* special chars */
 
354
        for (info = scm_special_char_table; info->esc_seq; info++) {
 
355
            if (c == info->code) {
 
356
                scm_port_puts(port, info->lex_rep);
 
357
                return;
 
358
            }
 
359
        }
 
360
 
 
361
        /* other control chars are printed in hexadecimal form */
 
362
        if (ICHAR_CONTROLP(c)) {
 
363
            scm_format(port, SCM_FMT_RAW_C, "x~02MX", (scm_int_t)c);
 
364
            return;
 
365
        }
 
366
        /* FALLTHROUGH */
 
367
    case AS_DISPLAY:
 
368
        scm_port_put_char(port, c);
 
369
        break;
 
370
 
 
371
    default:
 
372
        SCM_NOTREACHED;
 
373
    }
 
374
}
 
375
#endif /* SCM_USE_CHAR */
 
376
 
 
377
#if SCM_USE_STRING
 
378
static void
 
379
write_string(ScmObj port, ScmObj obj, enum OutputType otype)
 
380
{
 
381
#if SCM_USE_MULTIBYTE_CHAR
 
382
    ScmCharCodec *codec;
 
383
    ScmMultibyteString mbs;
 
384
    size_t len;
 
385
#else
 
386
    scm_int_t i, len;
 
387
#endif
 
388
    const ScmSpecialCharInfo *info;
 
389
    const char *str;
 
390
    scm_ichar_t c;
 
391
    DECLARE_INTERNAL_FUNCTION("write");
 
392
 
 
393
    str = SCM_STRING_STR(obj);
 
394
 
 
395
    switch (otype) {
 
396
    case AS_WRITE:
 
397
        scm_port_put_char(port, '\"'); /* opening doublequote */
 
398
#if SCM_USE_MULTIBYTE_CHAR
 
399
        if (scm_current_char_codec != scm_port_codec(port)) {
 
400
            /* Since the str does not have its encoding information, here
 
401
             * assumes that scm_current_char_codec is that. And then SigScheme
 
402
             * does not have an encoding conversion mechanism, puts it
 
403
             * as-is. */
 
404
            scm_port_puts(port, str);
 
405
        } else {
 
406
            len = strlen(str);
 
407
            codec = scm_port_codec(port);
 
408
            SCM_MBS_INIT2(mbs, str, len);
 
409
            while (SCM_MBS_GET_SIZE(mbs)) {
 
410
                c = SCM_CHARCODEC_READ_CHAR(codec, mbs);
 
411
#else /* SCM_USE_MULTIBYTE_CHAR */
 
412
            len = SCM_STRING_LEN(obj);
 
413
            for (i = 0; i < len; i++) {
 
414
                c = str[i];
 
415
#endif /* SCM_USE_MULTIBYTE_CHAR */
 
416
                for (info = scm_special_char_table; info->esc_seq; info++) {
 
417
                    if (c == info->code) {
 
418
                        scm_port_puts(port, info->esc_seq);
 
419
                        goto continue2;
 
420
                    }
 
421
                }
 
422
                scm_port_put_char(port, c);
 
423
            continue2:
 
424
                ;
 
425
            }
 
426
#if SCM_USE_MULTIBYTE_CHAR
 
427
        }
 
428
#endif
 
429
        scm_port_put_char(port, '\"'); /* closing doublequote */
 
430
        break;
 
431
 
 
432
    case AS_DISPLAY:
 
433
        scm_port_puts(port, str);
 
434
        break;
 
435
 
 
436
    default:
 
437
        SCM_NOTREACHED;
 
438
    }
 
439
}
 
440
#endif /* SCM_USE_STRING */
 
441
 
 
442
static void
 
443
write_list(ScmObj port, ScmObj lst, enum OutputType otype)
 
444
{
 
445
    ScmObj car;
 
446
#if SCM_USE_SRFI38
 
447
    size_t necessary_close_parens;
 
448
    scm_intobj_t index;
 
449
#endif
 
450
    DECLARE_INTERNAL_FUNCTION("write");
 
451
 
 
452
#if SCM_USE_SRFI38
 
453
    necessary_close_parens = 1;
 
454
  cheap_recursion:
 
455
#endif
 
456
 
 
457
    SCM_ASSERT(CONSP(lst));
 
458
 
 
459
    scm_port_put_char(port, '(');
 
460
 
 
461
    FOR_EACH (car, lst) {
 
462
        write_obj(port, car, otype);
 
463
        if (!CONSP(lst))
 
464
            break;
 
465
        scm_port_put_char(port, ' ');
 
466
 
 
467
#if SCM_USE_SRFI38
 
468
        /* See if the next pair is shared.  Note that the case
 
469
         * where the first pair is shared is handled in
 
470
         * write_obj(). */
 
471
        index = get_shared_index(lst);
 
472
        if (index > 0) {
 
473
            /* defined datum */
 
474
            scm_format(port, SCM_FMT_RAW_C, ". #~ZU#", (size_t)index);
 
475
            goto close_parens_and_return;
 
476
        }
 
477
        if (index < 0) {
 
478
            /* defining datum, with the new index negated */
 
479
            scm_format(port, SCM_FMT_RAW_C, ". #~ZU=", (size_t)-index);
 
480
            necessary_close_parens++;
 
481
            goto cheap_recursion;
 
482
        }
 
483
#endif
 
484
    }
 
485
 
 
486
    /* last item */
 
487
    if (!NULLP(lst)) {
 
488
        scm_port_puts(port, " . ");
 
489
        /* Callee takes care of shared data. */
 
490
        write_obj(port, lst, otype);
 
491
    }
 
492
 
 
493
#if SCM_USE_SRFI38
 
494
  close_parens_and_return:
 
495
    while (necessary_close_parens--)
 
496
#endif
 
497
        scm_port_put_char(port, ')');
 
498
}
 
499
 
 
500
#if SCM_USE_VECTOR
 
501
static void
 
502
write_vector(ScmObj port, ScmObj vec, enum OutputType otype)
 
503
{
 
504
    ScmObj *v;
 
505
    scm_int_t len, i;
 
506
 
 
507
    scm_port_puts(port, "#(");
 
508
 
 
509
    v = SCM_VECTOR_VEC(vec);
 
510
    len = SCM_VECTOR_LEN(vec);
 
511
    for (i = 0; i < len; i++) {
 
512
        if (i)
 
513
            scm_port_put_char(port, ' ');
 
514
        write_obj(port, v[i], otype);
 
515
    }
 
516
 
 
517
    scm_port_put_char(port, ')');
 
518
}
 
519
#endif /* SCM_USE_VECTOR */
 
520
 
 
521
static void
 
522
write_port(ScmObj port, ScmObj obj, enum OutputType otype)
 
523
{
 
524
    char *info;
 
525
 
 
526
    scm_port_puts(port, "#<");
 
527
 
 
528
    /* input or output */
 
529
    /* print "iport", "oport" or "ioport" if bidirectional port */
 
530
    if (SCM_PORT_FLAG(obj) & SCM_PORTFLAG_INPUT)
 
531
        scm_port_put_char(port, 'i');
 
532
    if (SCM_PORT_FLAG(obj) & SCM_PORTFLAG_OUTPUT)
 
533
        scm_port_put_char(port, 'o');
 
534
    scm_port_puts(port, "port");
 
535
 
 
536
    /* file or string */
 
537
    info = scm_port_inspect(obj);
 
538
    if (*info) {
 
539
        scm_port_put_char(port, ' ');
 
540
        scm_port_puts(port, info);
 
541
    }
 
542
    free(info);
 
543
 
 
544
    scm_port_put_char(port, '>');
 
545
}
 
546
 
 
547
static void
 
548
write_constant(ScmObj port, ScmObj obj, enum  OutputType otype)
 
549
{
 
550
    const char *str;
 
551
 
 
552
    if (EQ(obj, SCM_NULL))
 
553
        str = "()";
 
554
    else if (EQ(obj, SCM_TRUE))
 
555
        str = "#t";
 
556
    else if (EQ(obj, SCM_FALSE))
 
557
        str = "#f";
 
558
    else if (EQ(obj, SCM_EOF))
 
559
        str = "#<eof>";
 
560
    else if (EQ(obj, SCM_UNBOUND))
 
561
        str = "#<unbound>";
 
562
    else if (EQ(obj, SCM_UNDEF))
 
563
        str = "#<undef>";
 
564
    else
 
565
        SCM_NOTREACHED;
 
566
 
 
567
    scm_port_puts(port, str);
 
568
}
 
569
 
 
570
static void
 
571
write_errobj(ScmObj port, ScmObj obj, enum  OutputType otype)
 
572
{
 
573
    ScmObj err_obj_tag, reason, objs, trace_stack, elm;
 
574
    DECLARE_INTERNAL_FUNCTION("write");
 
575
 
 
576
    err_obj_tag = MUST_POP_ARG(obj);
 
577
    reason      = MUST_POP_ARG(obj);
 
578
    objs        = MUST_POP_ARG(obj);
 
579
    trace_stack = MUST_POP_ARG(obj);
 
580
    ASSERT_NO_MORE_ARG(obj);
 
581
 
 
582
    switch (otype) {
 
583
    case AS_WRITE:
 
584
        scm_port_puts(port, "#<error ");
 
585
        scm_write(port, reason);
 
586
        break;
 
587
 
 
588
    case AS_DISPLAY:
 
589
        scm_display(port, reason);
 
590
        break;
 
591
 
 
592
    default:
 
593
        SCM_NOTREACHED;
 
594
    }
 
595
 
 
596
    FOR_EACH (elm, objs) {
 
597
        scm_port_put_char(port, ' ');
 
598
        scm_write(port, elm);
 
599
    }
 
600
 
 
601
    if (otype == AS_WRITE)
 
602
        scm_port_put_char(port, '>');
 
603
}
 
604
 
 
605
#if SCM_USE_HYGIENIC_MACRO
 
606
static void
 
607
write_farsymbol(ScmObj port, ScmObj obj, enum  OutputType otype)
 
608
{
 
609
    /* Assumes that ScmPackedEnv is an integer. */
 
610
    scm_port_puts(port, "#<farsym");
 
611
    for (; SCM_FARSYMBOLP(obj); obj = SCM_FARSYMBOL_SYM(obj))
 
612
        scm_format(port, SCM_FMT_RAW_C, " ~MD ", SCM_FARSYMBOL_ENV(obj));
 
613
    scm_display(port, obj); /* Name. */
 
614
    scm_port_puts(port, ">");
 
615
}
 
616
#endif /* SCM_USE_HYGIENIC_MACRO */
 
617
 
 
618
#if SCM_USE_SRFI38
 
619
static void
 
620
hash_grow(hash_table *tab)
 
621
{
 
622
    size_t old_size, new_size, i;
 
623
    hash_entry *old_ents;
 
624
 
 
625
    old_size = tab->size;
 
626
    new_size = old_size * 2;
 
627
    old_ents = tab->ents;
 
628
 
 
629
    tab->ents = scm_calloc(new_size, sizeof(hash_entry));
 
630
    tab->size = new_size;
 
631
    tab->used = 0;
 
632
 
 
633
    for (i = 0; i < old_size; i++)
 
634
        hash_lookup(tab, old_ents[i].key, old_ents[i].datum, HASH_INSERT);
 
635
 
 
636
    free(old_ents);
 
637
}
 
638
 
 
639
/**
 
640
 * @return A pointer to the entry, or NULL if not found.
 
641
 */
 
642
static hash_entry *
 
643
hash_lookup(hash_table *tab, ScmObj key, scm_intobj_t datum, int flag)
 
644
{
 
645
    size_t i;
 
646
    hashval_t hashval;
 
647
    hash_entry *ent;
 
648
 
 
649
    /* If we have > 32 bits, we'll discard some of them.  The lower
 
650
     * bits are zeroed for alignment or used for tag bits, and in the
 
651
     * latter case, the tag can only take 3 values: pair, string, or
 
652
     * vector.  We'll drop these bits.  KEYs are expected to be
 
653
     * pointers into the heap, so their higher bis are probably
 
654
     * uniform.  I haven't confirmed either's validity, though. */
 
655
    hashval = (hashval_t)key;
 
656
    if (sizeof(hashval) > 4) {
 
657
        hashval /= sizeof(ScmCell);
 
658
        hashval &= 0xffffffff;
 
659
    }
 
660
 
 
661
    hashval *= 2654435761UL; /* golden ratio hash */
 
662
 
 
663
    /* We probe linearly, since a) speed isn't a primary concern for
 
664
     * SigScheme, and b) having a table of primes only for this
 
665
     * purpose is probably just a waste. */
 
666
    for (i = 0; i < tab->size; i++) {
 
667
        ent = &(tab->ents)[(hashval + i) & (tab->size - 1)];
 
668
        if (!OCCUPIED(ent)) {
 
669
            if (flag & HASH_INSERT) {
 
670
                ent->key = key;
 
671
                ent->datum = datum;
 
672
                tab->used++;
 
673
 
 
674
                /* used > size * 2/3 --> overpopulated */
 
675
                if (tab->used * 3 > tab->size * 2)
 
676
                    hash_grow(tab);
 
677
            }
 
678
            return NULL;
 
679
        }
 
680
        if (EQ(ent->key, key))
 
681
            return ent;
 
682
    }
 
683
 
 
684
    /* A linear probe should always find a slot. */
 
685
    SCM_NOTREACHED;
 
686
}
 
687
 
 
688
/**
 
689
 * Find out what non-atomic objects a structure shares within itself.
 
690
 * @param obj The object in question, or a part of it.
 
691
 * @param ctx Where to put the scan results.
 
692
 */
 
693
static void
 
694
write_ss_scan(ScmObj obj, write_ss_context *ctx)
 
695
{
 
696
#if SCM_USE_VECTOR
 
697
    scm_int_t i, len;
 
698
#endif
 
699
    hash_entry *ent;
 
700
    ScmObj err_obj_tag, reason, objs, trace_stack;
 
701
    DECLARE_INTERNAL_FUNCTION("write-with-shared-structure");
 
702
 
 
703
    if (ERROBJP(obj)) {
 
704
        err_obj_tag = MUST_POP_ARG(obj);
 
705
        reason      = MUST_POP_ARG(obj);
 
706
        objs        = MUST_POP_ARG(obj);
 
707
        trace_stack = MUST_POP_ARG(obj);
 
708
        ASSERT_NO_MORE_ARG(obj);
 
709
 
 
710
        write_ss_scan(reason, ctx);
 
711
        write_ss_scan(objs, ctx);
 
712
        return;
 
713
    }
 
714
 
 
715
    /* (for-each mark-as-seen-or-return-if-familiar obj) */
 
716
    for (; CONSP(obj); obj = CDR(obj)) {
 
717
        ent = hash_lookup(&ctx->seen, obj, NONDEFINING_DATUM, HASH_INSERT);
 
718
        if (ent) {
 
719
            ent->datum = DEFINING_DATUM;
 
720
            return;
 
721
        }
 
722
        write_ss_scan(CAR(obj), ctx);
 
723
    }
 
724
 
 
725
    if (INTERESTINGP(obj)) {
 
726
        ent = hash_lookup(&ctx->seen, obj, NONDEFINING_DATUM, HASH_INSERT);
 
727
        if (ent) {
 
728
            ent->datum = DEFINING_DATUM;
 
729
            return;
 
730
        }
 
731
        switch (SCM_TYPE(obj)) {
 
732
        case ScmClosure:
 
733
            /* We don't need to track env because it's not printed anyway. */
 
734
            write_ss_scan(SCM_CLOSURE_EXP(obj), ctx);
 
735
            break;
 
736
 
 
737
        case ScmValuePacket:
 
738
#if SCM_USE_VALUECONS
 
739
#if SCM_USE_STORAGE_FATTY
 
740
            if (!SCM_NULLVALUESP(obj)) {
 
741
                /* EQ(obj, SCM_VALUEPACKET_VALUES(obj)) */
 
742
                write_ss_scan(CDR(SCM_VALUEPACKET_VALUES(obj)), ctx);
 
743
                /* SCM_VALUEPACKET_VALUES() changes the type destructively */
 
744
                SCM_ENTYPE(obj, ScmValuePacket);
 
745
            }
 
746
#else /* SCM_USE_STORAGE_FATTY */
 
747
#error "valuecons is not supported on this storage implementation"
 
748
#endif /* SCM_USE_STORAGE_FATTY */
 
749
#else /* SCM_USE_VALUECONS */
 
750
            write_ss_scan(SCM_VALUEPACKET_VALUES(obj), ctx);
 
751
#endif /* SCM_USE_VALUECONS */
 
752
            break;
 
753
 
 
754
#if SCM_USE_VECTOR
 
755
        case ScmVector:
 
756
            for (i = 0, len = SCM_VECTOR_LEN(obj); i < len; i++)
 
757
                write_ss_scan(SCM_VECTOR_VEC(obj)[i], ctx);
 
758
            break;
 
759
#endif /* SCM_USE_VECTOR */
 
760
 
 
761
        default:
 
762
            break;
 
763
        }
 
764
    }
 
765
}
 
766
 
 
767
/**
 
768
 * @return The index for obj, if it's a defined datum.  If it's a
 
769
 *         defining datum, allocate an index for it and return the
 
770
 *         *additive inverse* of the index.  If obj is nondefining,
 
771
 *         return zero.
 
772
 */
 
773
static scm_intobj_t
 
774
get_shared_index(ScmObj obj)
 
775
{
 
776
    hash_entry *ent;
 
777
 
 
778
    if (l_write_ss_ctx) {
 
779
        ent = hash_lookup(&l_write_ss_ctx->seen, obj, 0, HASH_FIND);
 
780
 
 
781
        if (ent) {
 
782
            if (ent->datum == DEFINING_DATUM) {
 
783
                ent->datum = l_write_ss_ctx->next_index++;
 
784
                return -(ent->datum);
 
785
            }
 
786
            return ent->datum;
 
787
        }
 
788
    }
 
789
    return 0;
 
790
}
 
791
 
 
792
static void
 
793
write_ss_internal(ScmObj port, ScmObj obj, enum OutputType otype)
 
794
{
 
795
    write_ss_context ctx = {{0}};
 
796
    size_t i;
 
797
 
 
798
    ctx.next_index = 1;
 
799
    ctx.seen.size = 1 << 8; /* arbitrary initial size */
 
800
    ctx.seen.ents = scm_calloc(ctx.seen.size, sizeof(hash_entry));
 
801
    for (i = 0; i < ctx.seen.size; i++) {
 
802
        ctx.seen.ents[i].key = SCM_INVALID;
 
803
    }
 
804
 
 
805
    write_ss_scan(obj, &ctx);
 
806
 
 
807
    /* If no structure is shared, we do a normal write. */
 
808
    if (!HASH_EMPTY(ctx.seen))
 
809
        l_write_ss_ctx = &ctx;
 
810
 
 
811
    write_internal(port, obj, otype);
 
812
 
 
813
    l_write_ss_ctx = NULL;
 
814
    free(ctx.seen.ents);
 
815
}
 
816
 
 
817
/* write with shared structure */
 
818
SCM_EXPORT void
 
819
scm_write_ss(ScmObj port, ScmObj obj)
 
820
{
 
821
    write_ss_internal(port, obj, AS_WRITE);
 
822
}
 
823
 
 
824
SCM_EXPORT void
 
825
scm_display_errobj_ss(ScmObj port, ScmObj errobj)
 
826
{
 
827
    write_ss_internal(port, errobj, AS_DISPLAY);
 
828
}
 
829
#endif /* SCM_USE_SRFI38 */
 
830
 
 
831
/*===========================================================================
 
832
  R5RS : 6.6 Input and Output : 6.6.3 Output
 
833
===========================================================================*/
 
834
SCM_EXPORT ScmObj
 
835
scm_p_write(ScmObj obj, ScmObj args)
 
836
{
 
837
    ScmObj port;
 
838
    DECLARE_FUNCTION("write", procedure_variadic_1);
 
839
 
 
840
    port = scm_prepare_port(args, scm_out);
 
841
    scm_write(port, obj);
 
842
    return SCM_UNDEF;
 
843
}
 
844
 
 
845
SCM_EXPORT ScmObj
 
846
scm_p_display(ScmObj obj, ScmObj args)
 
847
{
 
848
    ScmObj port;
 
849
    DECLARE_FUNCTION("display", procedure_variadic_1);
 
850
 
 
851
    port = scm_prepare_port(args, scm_out);
 
852
    scm_display(port, obj);
 
853
    return SCM_UNDEF;
 
854
}