Implementation of SRFI-98 (An interface to access environment variables).
[bpt/guile.git] / libguile / smob.c
CommitLineData
202271f2 1/* Copyright (C) 1995,1996,1998,1999,2000,2001, 2003, 2004, 2006, 2009 Free Software Foundation, Inc.
0f2d19dd 2 *
73be1d9e
MV
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.
0f2d19dd 7 *
73be1d9e
MV
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.
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
92205699 15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
73be1d9e 16 */
1bbd0b84 17
1bbd0b84 18
0f2d19dd 19\f
dbb605f5 20#ifdef HAVE_CONFIG_H
f9fe039d
RB
21# include <config.h>
22#endif
0f2d19dd
JB
23
24#include <stdio.h>
e6e2e95a
MD
25#include <errno.h>
26
a0599745 27#include "libguile/_scm.h"
20e6290e 28
4e047c3e 29#include "libguile/async.h"
a0599745 30#include "libguile/objects.h"
9511876f 31#include "libguile/goops.h"
a0599745 32#include "libguile/ports.h"
d7ec6b9f 33
0f2d19dd
JB
34#ifdef HAVE_MALLOC_H
35#include <malloc.h>
36#endif
37
a0599745 38#include "libguile/smob.h"
9dd5943c 39
0f2d19dd
JB
40\f
41
42/* scm_smobs scm_numsmob
7a7f7c53 43 * implement a fixed sized array of smob records.
0f2d19dd
JB
44 * Indexes into this table are used when generating type
45 * tags for smobjects (if you know a tag you can get an index and conversely).
46 */
7a7f7c53 47
202271f2
LC
48#define MAX_SMOB_COUNT SCM_I_MAX_SMOB_TYPE_COUNT
49
c014a02e 50long scm_numsmob;
7a7f7c53 51scm_smob_descriptor scm_smobs[MAX_SMOB_COUNT];
0f2d19dd 52
37fc18ae
MV
53/* Lower 16 bit of data must be zero.
54*/
55void
56scm_i_set_smob_flags (SCM x, scm_t_bits data)
57{
58 SCM_SET_CELL_WORD_0 (x, (SCM_CELL_WORD_0 (x) & 0xFFFF) | data);
59}
60
197b0573
MV
61void
62scm_assert_smob_type (scm_t_bits tag, SCM val)
63{
64 if (!SCM_SMOB_PREDICATE (tag, val))
65 scm_wrong_type_arg_msg (NULL, 0, val, scm_smobs[SCM_TC2SMOBNUM(tag)].name);
66}
67
9dd5943c
MD
68/* {Mark}
69 */
70
71/* This function is vestigial. It used to be the mark function's
72 responsibility to set the mark bit on the smob or port, but now the
73 generic marking routine in gc.c takes care of that, and a zero
74 pointer for a mark function means "don't bother". So you never
75 need scm_mark0.
76
77 However, we leave it here because it's harmless to call it, and
78 people out there have smob code that uses it, and there's no reason
79 to make their links fail. */
80
81SCM
e81d98ec 82scm_mark0 (SCM ptr SCM_UNUSED)
9dd5943c
MD
83{
84 return SCM_BOOL_F;
85}
86
87SCM
22a52da1
DH
88/* Dirk::FIXME: The name markcdr is misleading, since the term cdr should only
89 be used for real pairs. */
6e8d25a6 90scm_markcdr (SCM ptr)
9dd5943c 91{
22a52da1 92 return SCM_CELL_OBJECT_1 (ptr);
9dd5943c
MD
93}
94
95/* {Free}
96 */
97
1be6b49c 98size_t
e81d98ec 99scm_free0 (SCM ptr SCM_UNUSED)
9dd5943c
MD
100{
101 return 0;
102}
103
1be6b49c 104size_t
9dd5943c
MD
105scm_smob_free (SCM obj)
106{
4c9419ac
MV
107 long n = SCM_SMOBNUM (obj);
108 if (scm_smobs[n].size > 0)
109 scm_gc_free ((void *) SCM_CELL_WORD_1 (obj),
110 scm_smobs[n].size, SCM_SMOBNAME (n));
111 return 0;
9dd5943c
MD
112}
113
114/* {Print}
115 */
116
117int
e81d98ec 118scm_smob_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
9dd5943c 119{
c014a02e 120 long n = SCM_SMOBNUM (exp);
9dd5943c 121 scm_puts ("#<", port);
2c16a78a 122 scm_puts (SCM_SMOBNAME (n) ? SCM_SMOBNAME (n) : "smob", port);
9dd5943c 123 scm_putc (' ', port);
7a7f7c53 124 if (scm_smobs[n].size)
0345e278 125 scm_uintprint (SCM_CELL_WORD_1 (exp), 16, port);
7a7f7c53 126 else
0345e278 127 scm_uintprint (SCM_UNPACK (exp), 16, port);
9dd5943c
MD
128 scm_putc ('>', port);
129 return 1;
130}
1cc91f1b 131
0717dfd8
KN
132/* {Apply}
133 */
134
cb1c46c5
KN
135#define SCM_SMOB_APPLY0(SMOB) \
136 SCM_SMOB_DESCRIPTOR (SMOB).apply (SMOB)
34d19ef6 137#define SCM_SMOB_APPLY1(SMOB, A1) \
cb1c46c5 138 SCM_SMOB_DESCRIPTOR (SMOB).apply (SMOB, A1)
34d19ef6 139#define SCM_SMOB_APPLY2(SMOB, A1, A2) \
cb1c46c5 140 SCM_SMOB_DESCRIPTOR (SMOB).apply (SMOB, A1, A2)
34d19ef6 141#define SCM_SMOB_APPLY3(SMOB, A1, A2, A3) \
cb1c46c5
KN
142 SCM_SMOB_DESCRIPTOR (SMOB).apply (SMOB, A1, A2, A3)
143
cb1c46c5
KN
144static SCM
145scm_smob_apply_0_010 (SCM smob)
0717dfd8 146{
cb1c46c5 147 return SCM_SMOB_APPLY1 (smob, SCM_UNDEFINED);
0717dfd8
KN
148}
149
cb1c46c5
KN
150static SCM
151scm_smob_apply_0_020 (SCM smob)
0717dfd8 152{
cb1c46c5 153 return SCM_SMOB_APPLY2 (smob, SCM_UNDEFINED, SCM_UNDEFINED);
0717dfd8
KN
154}
155
cb1c46c5
KN
156static SCM
157scm_smob_apply_0_030 (SCM smob)
0717dfd8 158{
cb1c46c5 159 return SCM_SMOB_APPLY3 (smob, SCM_UNDEFINED, SCM_UNDEFINED, SCM_UNDEFINED);
0717dfd8
KN
160}
161
cb1c46c5
KN
162static SCM
163scm_smob_apply_0_001 (SCM smob)
0717dfd8 164{
cb1c46c5
KN
165 return SCM_SMOB_APPLY1 (smob, SCM_EOL);
166}
167
168static SCM
169scm_smob_apply_0_011 (SCM smob)
170{
171 return SCM_SMOB_APPLY2 (smob, SCM_UNDEFINED, SCM_EOL);
172}
173
174static SCM
175scm_smob_apply_0_021 (SCM smob)
176{
177 return SCM_SMOB_APPLY3 (smob, SCM_UNDEFINED, SCM_UNDEFINED, SCM_EOL);
178}
179
180static SCM
181scm_smob_apply_0_error (SCM smob)
182{
183 scm_wrong_num_args (smob);
184}
185
cb1c46c5
KN
186static SCM
187scm_smob_apply_1_020 (SCM smob, SCM a1)
188{
189 return SCM_SMOB_APPLY2 (smob, a1, SCM_UNDEFINED);
190}
191
192static SCM
193scm_smob_apply_1_030 (SCM smob, SCM a1)
194{
195 return SCM_SMOB_APPLY3 (smob, a1, SCM_UNDEFINED, SCM_UNDEFINED);
196}
197
198static SCM
199scm_smob_apply_1_001 (SCM smob, SCM a1)
200{
1afff620 201 return SCM_SMOB_APPLY1 (smob, scm_list_1 (a1));
cb1c46c5
KN
202}
203
204static SCM
205scm_smob_apply_1_011 (SCM smob, SCM a1)
206{
207 return SCM_SMOB_APPLY2 (smob, a1, SCM_EOL);
208}
209
210static SCM
211scm_smob_apply_1_021 (SCM smob, SCM a1)
212{
213 return SCM_SMOB_APPLY3 (smob, a1, SCM_UNDEFINED, SCM_EOL);
214}
215
216static SCM
e81d98ec 217scm_smob_apply_1_error (SCM smob, SCM a1 SCM_UNUSED)
cb1c46c5
KN
218{
219 scm_wrong_num_args (smob);
220}
221
cb1c46c5
KN
222static SCM
223scm_smob_apply_2_030 (SCM smob, SCM a1, SCM a2)
224{
225 return SCM_SMOB_APPLY3 (smob, a1, a2, SCM_UNDEFINED);
226}
227
228static SCM
229scm_smob_apply_2_001 (SCM smob, SCM a1, SCM a2)
230{
1afff620 231 return SCM_SMOB_APPLY1 (smob, scm_list_2 (a1, a2));
7c58e21b 232}
cb1c46c5
KN
233
234static SCM
235scm_smob_apply_2_011 (SCM smob, SCM a1, SCM a2)
236{
1afff620 237 return SCM_SMOB_APPLY2 (smob, a1, scm_list_1 (a2));
cb1c46c5
KN
238}
239
240static SCM
241scm_smob_apply_2_021 (SCM smob, SCM a1, SCM a2)
242{
243 return SCM_SMOB_APPLY3 (smob, a1, a2, SCM_EOL);
244}
245
246static SCM
e81d98ec 247scm_smob_apply_2_error (SCM smob, SCM a1 SCM_UNUSED, SCM a2 SCM_UNUSED)
cb1c46c5
KN
248{
249 scm_wrong_num_args (smob);
250}
251
252static SCM
253scm_smob_apply_3_030 (SCM smob, SCM a1, SCM a2, SCM rst)
254{
d2e53ed6 255 if (!scm_is_null (SCM_CDR (rst)))
cb1c46c5
KN
256 scm_wrong_num_args (smob);
257 return SCM_SMOB_APPLY3 (smob, a1, a2, SCM_CAR (rst));
258}
259
260static SCM
261scm_smob_apply_3_001 (SCM smob, SCM a1, SCM a2, SCM rst)
262{
263 return SCM_SMOB_APPLY1 (smob, scm_cons2 (a1, a2, rst));
0717dfd8
KN
264}
265
cb1c46c5
KN
266static SCM
267scm_smob_apply_3_011 (SCM smob, SCM a1, SCM a2, SCM rst)
268{
269 return SCM_SMOB_APPLY2 (smob, a1, scm_cons (a2, rst));
270}
271
272static SCM
273scm_smob_apply_3_021 (SCM smob, SCM a1, SCM a2, SCM rst)
274{
275 return SCM_SMOB_APPLY3 (smob, a1, a2, rst);
276}
277
278static SCM
e81d98ec
DH
279scm_smob_apply_3_error (SCM smob,
280 SCM a1 SCM_UNUSED,
281 SCM a2 SCM_UNUSED,
282 SCM rst SCM_UNUSED)
cb1c46c5
KN
283{
284 scm_wrong_num_args (smob);
285}
286
287\f
7a7f7c53 288
92c2555f 289scm_t_bits
da0e6c2b 290scm_make_smob_type (char const *name, size_t size)
7a7f7c53 291#define FUNC_NAME "scm_make_smob_type"
0f2d19dd 292{
c014a02e 293 long new_smob;
7a7f7c53 294
9de87eea 295 SCM_CRITICAL_SECTION_START;
7a7f7c53
DH
296 new_smob = scm_numsmob;
297 if (scm_numsmob != MAX_SMOB_COUNT)
298 ++scm_numsmob;
9de87eea 299 SCM_CRITICAL_SECTION_END;
7a7f7c53
DH
300
301 if (new_smob == MAX_SMOB_COUNT)
302 scm_misc_error (FUNC_NAME, "maximum number of smobs exceeded", SCM_EOL);
303
304 scm_smobs[new_smob].name = name;
305 if (size != 0)
2500356c 306 {
7a7f7c53
DH
307 scm_smobs[new_smob].size = size;
308 scm_smobs[new_smob].free = scm_smob_free;
2500356c 309 }
7a7f7c53 310
d7ec6b9f 311 /* Make a class object if Goops is present. */
04795a1c 312 if (SCM_UNPACK (scm_smob_class[0]) != 0)
74b6d6e4 313 scm_smob_class[new_smob] = scm_make_extended_class (name, 0);
7a7f7c53
DH
314
315 return scm_tc7_smob + new_smob * 256;
0f2d19dd 316}
7a7f7c53
DH
317#undef FUNC_NAME
318
0f2d19dd 319
9dd5943c 320void
92c2555f 321scm_set_smob_mark (scm_t_bits tc, SCM (*mark) (SCM))
9dd5943c
MD
322{
323 scm_smobs[SCM_TC2SMOBNUM (tc)].mark = mark;
324}
325
326void
92c2555f 327scm_set_smob_free (scm_t_bits tc, size_t (*free) (SCM))
9dd5943c
MD
328{
329 scm_smobs[SCM_TC2SMOBNUM (tc)].free = free;
330}
331
332void
92c2555f 333scm_set_smob_print (scm_t_bits tc, int (*print) (SCM, SCM, scm_print_state*))
9dd5943c
MD
334{
335 scm_smobs[SCM_TC2SMOBNUM (tc)].print = print;
336}
337
338void
92c2555f 339scm_set_smob_equalp (scm_t_bits tc, SCM (*equalp) (SCM, SCM))
9dd5943c
MD
340{
341 scm_smobs[SCM_TC2SMOBNUM (tc)].equalp = equalp;
342}
343
0717dfd8 344void
92c2555f 345scm_set_smob_apply (scm_t_bits tc, SCM (*apply) (),
7c58e21b 346 unsigned int req, unsigned int opt, unsigned int rst)
0717dfd8 347{
cb1c46c5
KN
348 SCM (*apply_0) (SCM);
349 SCM (*apply_1) (SCM, SCM);
350 SCM (*apply_2) (SCM, SCM, SCM);
351 SCM (*apply_3) (SCM, SCM, SCM, SCM);
352 int type = SCM_GSUBR_MAKTYPE (req, opt, rst);
353
7c58e21b 354 if (rst > 1 || req + opt + rst > 3)
cb1c46c5
KN
355 {
356 puts ("Unsupported smob application type");
357 abort ();
358 }
359
360 switch (type)
361 {
362 case SCM_GSUBR_MAKTYPE (0, 0, 0):
7c58e21b 363 apply_0 = apply; break;
cb1c46c5
KN
364 case SCM_GSUBR_MAKTYPE (0, 1, 0):
365 apply_0 = scm_smob_apply_0_010; break;
366 case SCM_GSUBR_MAKTYPE (0, 2, 0):
367 apply_0 = scm_smob_apply_0_020; break;
368 case SCM_GSUBR_MAKTYPE (0, 3, 0):
369 apply_0 = scm_smob_apply_0_030; break;
370 case SCM_GSUBR_MAKTYPE (0, 0, 1):
371 apply_0 = scm_smob_apply_0_001; break;
372 case SCM_GSUBR_MAKTYPE (0, 1, 1):
373 apply_0 = scm_smob_apply_0_011; break;
374 case SCM_GSUBR_MAKTYPE (0, 2, 1):
375 apply_0 = scm_smob_apply_0_021; break;
376 default:
377 apply_0 = scm_smob_apply_0_error; break;
378 }
379
380 switch (type)
381 {
382 case SCM_GSUBR_MAKTYPE (1, 0, 0):
383 case SCM_GSUBR_MAKTYPE (0, 1, 0):
7c58e21b 384 apply_1 = apply; break;
cb1c46c5
KN
385 case SCM_GSUBR_MAKTYPE (1, 1, 0):
386 case SCM_GSUBR_MAKTYPE (0, 2, 0):
387 apply_1 = scm_smob_apply_1_020; break;
388 case SCM_GSUBR_MAKTYPE (1, 2, 0):
389 case SCM_GSUBR_MAKTYPE (0, 3, 0):
390 apply_1 = scm_smob_apply_1_030; break;
391 case SCM_GSUBR_MAKTYPE (0, 0, 1):
392 apply_1 = scm_smob_apply_1_001; break;
393 case SCM_GSUBR_MAKTYPE (1, 0, 1):
394 case SCM_GSUBR_MAKTYPE (0, 1, 1):
395 apply_1 = scm_smob_apply_1_011; break;
396 case SCM_GSUBR_MAKTYPE (1, 1, 1):
397 case SCM_GSUBR_MAKTYPE (0, 2, 1):
398 apply_1 = scm_smob_apply_1_021; break;
399 default:
400 apply_1 = scm_smob_apply_1_error; break;
401 }
402
403 switch (type)
404 {
405 case SCM_GSUBR_MAKTYPE (2, 0, 0):
406 case SCM_GSUBR_MAKTYPE (1, 1, 0):
407 case SCM_GSUBR_MAKTYPE (0, 2, 0):
7c58e21b 408 apply_2 = apply; break;
cb1c46c5
KN
409 case SCM_GSUBR_MAKTYPE (2, 1, 0):
410 case SCM_GSUBR_MAKTYPE (1, 2, 0):
411 case SCM_GSUBR_MAKTYPE (0, 3, 0):
412 apply_2 = scm_smob_apply_2_030; break;
413 case SCM_GSUBR_MAKTYPE (0, 0, 1):
414 apply_2 = scm_smob_apply_2_001; break;
415 case SCM_GSUBR_MAKTYPE (1, 0, 1):
416 case SCM_GSUBR_MAKTYPE (0, 1, 1):
417 apply_2 = scm_smob_apply_2_011; break;
418 case SCM_GSUBR_MAKTYPE (2, 0, 1):
419 case SCM_GSUBR_MAKTYPE (1, 1, 1):
420 case SCM_GSUBR_MAKTYPE (0, 2, 1):
421 apply_2 = scm_smob_apply_2_021; break;
422 default:
423 apply_2 = scm_smob_apply_2_error; break;
424 }
425
426 switch (type)
427 {
428 case SCM_GSUBR_MAKTYPE (3, 0, 0):
429 case SCM_GSUBR_MAKTYPE (2, 1, 0):
430 case SCM_GSUBR_MAKTYPE (1, 2, 0):
431 case SCM_GSUBR_MAKTYPE (0, 3, 0):
432 apply_3 = scm_smob_apply_3_030; break;
433 case SCM_GSUBR_MAKTYPE (0, 0, 1):
434 apply_3 = scm_smob_apply_3_001; break;
435 case SCM_GSUBR_MAKTYPE (1, 0, 1):
436 case SCM_GSUBR_MAKTYPE (0, 1, 1):
437 apply_3 = scm_smob_apply_3_011; break;
438 case SCM_GSUBR_MAKTYPE (2, 0, 1):
439 case SCM_GSUBR_MAKTYPE (1, 1, 1):
440 case SCM_GSUBR_MAKTYPE (0, 2, 1):
441 apply_3 = scm_smob_apply_3_021; break;
442 default:
443 apply_3 = scm_smob_apply_3_error; break;
444 }
445
03416a99 446 scm_smobs[SCM_TC2SMOBNUM (tc)].apply = apply;
cb1c46c5
KN
447 scm_smobs[SCM_TC2SMOBNUM (tc)].apply_0 = apply_0;
448 scm_smobs[SCM_TC2SMOBNUM (tc)].apply_1 = apply_1;
449 scm_smobs[SCM_TC2SMOBNUM (tc)].apply_2 = apply_2;
450 scm_smobs[SCM_TC2SMOBNUM (tc)].apply_3 = apply_3;
68b06924 451 scm_smobs[SCM_TC2SMOBNUM (tc)].gsubr_type = type;
04795a1c
LC
452
453 if (SCM_UNPACK (scm_smob_class[0]) != 0)
74b6d6e4 454 scm_i_inherit_applicable (scm_smob_class[SCM_TC2SMOBNUM (tc)]);
0717dfd8
KN
455}
456
9dd5943c 457SCM
92c2555f 458scm_make_smob (scm_t_bits tc)
9dd5943c 459{
c014a02e 460 long n = SCM_TC2SMOBNUM (tc);
1be6b49c 461 size_t size = scm_smobs[n].size;
16d4699b 462 scm_t_bits data = (size > 0
4c9419ac 463 ? (scm_t_bits) scm_gc_malloc (size, SCM_SMOBNAME (n))
16d4699b 464 : 0);
228a24ef 465 return scm_cell (tc, data);
9dd5943c
MD
466}
467
ceef3208 468\f
534c55a9 469/* {Initialization for the type of free cells}
0f2d19dd
JB
470 */
471
ceef3208 472static int
e81d98ec 473free_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
ceef3208
JB
474{
475 char buf[100];
e841c3e0
KN
476 sprintf (buf, "#<freed cell %p; GC missed a reference>",
477 (void *) SCM_UNPACK (exp));
ceef3208 478 scm_puts (buf, port);
1e71eafb
HWN
479
480#if (SCM_DEBUG_CELL_ACCESSES == 1)
481 if (scm_debug_cell_accesses_p)
482 abort();
483#endif
484
ceef3208
JB
485
486 return 1;
487}
488
0f2d19dd
JB
489void
490scm_smob_prehistory ()
0f2d19dd 491{
c014a02e 492 long i;
92c2555f 493 scm_t_bits tc;
e841c3e0 494
0f2d19dd 495 scm_numsmob = 0;
7a7f7c53
DH
496 for (i = 0; i < MAX_SMOB_COUNT; ++i)
497 {
498 scm_smobs[i].name = 0;
499 scm_smobs[i].size = 0;
500 scm_smobs[i].mark = 0;
501 scm_smobs[i].free = 0;
502 scm_smobs[i].print = scm_smob_print;
503 scm_smobs[i].equalp = 0;
504 scm_smobs[i].apply = 0;
505 scm_smobs[i].apply_0 = 0;
506 scm_smobs[i].apply_1 = 0;
507 scm_smobs[i].apply_2 = 0;
508 scm_smobs[i].apply_3 = 0;
509 scm_smobs[i].gsubr_type = 0;
510 }
9dd5943c 511
534c55a9 512 /* WARNING: This scm_make_smob_type call must be done first. */
e841c3e0
KN
513 tc = scm_make_smob_type ("free", 0);
514 scm_set_smob_print (tc, free_print);
0f2d19dd 515}
89e00824
ML
516
517/*
518 Local Variables:
519 c-file-style: "gnu"
520 End:
521*/