doc: Remove reference to `closure?', now deprecated.
[bpt/guile.git] / libguile / struct.c
CommitLineData
75ba64d6 1/* Copyright (C) 1996,1997,1998,1999,2000,2001, 2003, 2004, 2006, 2007, 2008, 2009, 2010, 2011, 2012 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
0f2d19dd 19\f
dbb605f5 20#ifdef HAVE_CONFIG_H
a6f7f57d
RB
21# include <config.h>
22#endif
0f2d19dd 23
66e78727 24#include <alloca.h>
aa42c036 25#include <assert.h>
66e78727 26
a0599745 27#include "libguile/_scm.h"
4e047c3e 28#include "libguile/async.h"
a0599745
MD
29#include "libguile/chars.h"
30#include "libguile/eval.h"
31#include "libguile/alist.h"
32#include "libguile/weaks.h"
33#include "libguile/hashtab.h"
34#include "libguile/ports.h"
35#include "libguile/strings.h"
27646f41 36#include "libguile/srfi-13.h"
a0599745
MD
37
38#include "libguile/validate.h"
39#include "libguile/struct.h"
0f2d19dd 40
d15ad007
LC
41#include "libguile/eq.h"
42
95b88819
GH
43#ifdef HAVE_STRING_H
44#include <string.h>
45#endif
46
1c44468d 47#include "libguile/bdw-gc.h"
5e67dc27 48
0f2d19dd
JB
49\f
50
b6cf4d02
AW
51/* A needlessly obscure test. */
52#define SCM_LAYOUT_TAILP(X) (((X) & 32) == 0) /* R, W or O */
53
0f2d19dd 54static SCM required_vtable_fields = SCM_BOOL_F;
b6cf4d02
AW
55static SCM required_applicable_fields = SCM_BOOL_F;
56static SCM required_applicable_with_setter_fields = SCM_BOOL_F;
db5ed685
AW
57SCM scm_applicable_struct_vtable_vtable;
58SCM scm_applicable_struct_with_setter_vtable_vtable;
59SCM scm_standard_vtable_vtable;
60
0f2d19dd
JB
61
62\f
a1ec6916 63SCM_DEFINE (scm_make_struct_layout, "make-struct-layout", 1, 0, 0,
1bbd0b84 64 (SCM fields),
b380b885 65 "Return a new structure layout object.\n\n"
7c31152f 66 "@var{fields} must be a string made up of pairs of characters\n"
b380b885
MD
67 "strung together. The first character of each pair describes a field\n"
68 "type, the second a field protection. Allowed types are 'p' for\n"
69 "GC-protected Scheme data, 'u' for unprotected binary data, and 's' for\n"
04323af4 70 "a field that points to the structure itself. Allowed protections\n"
b6cf4d02
AW
71 "are 'w' for mutable fields, 'h' for hidden fields, 'r' for read-only\n"
72 "fields, and 'o' for opaque fields.\n\n"
73 "Hidden fields are writable, but they will not consume an initializer arg\n"
74 "passed to @code{make-struct}. They are useful to add slots to a struct\n"
75 "in a way that preserves backward-compatibility with existing calls to\n"
76 "@code{make-struct}, especially for derived vtables.\n\n"
77 "The last field protection specification may be capitalized to indicate\n"
78 "that the field is a tail-array.")
1bbd0b84 79#define FUNC_NAME s_scm_make_struct_layout
0f2d19dd
JB
80{
81 SCM new_sym;
27646f41 82 scm_t_wchar c;
2ade72d7 83
7f991c7d
LC
84 SCM_VALIDATE_STRING (1, fields);
85
1bbd0b84 86 { /* scope */
1be6b49c 87 size_t len;
0f2d19dd
JB
88 int x;
89
cc95e00a 90 len = scm_i_string_length (fields);
2ade72d7
DH
91 if (len % 2 == 1)
92 SCM_MISC_ERROR ("odd length field specification: ~S",
1afff620 93 scm_list_1 (fields));
2ade72d7 94
0f2d19dd
JB
95 for (x = 0; x < len; x += 2)
96 {
27646f41 97 switch (c = scm_i_string_ref (fields, x))
0f2d19dd
JB
98 {
99 case 'u':
100 case 'p':
101#if 0
102 case 'i':
103 case 'd':
104#endif
105 case 's':
106 break;
107 default:
2ade72d7 108 SCM_MISC_ERROR ("unrecognized field type: ~S",
27646f41 109 scm_list_1 (SCM_MAKE_CHAR (c)));
0f2d19dd
JB
110 }
111
27646f41 112 switch (c = scm_i_string_ref (fields, x + 1))
0f2d19dd
JB
113 {
114 case 'w':
b6cf4d02 115 case 'h':
27646f41 116 if (scm_i_string_ref (fields, x) == 's')
2ade72d7 117 SCM_MISC_ERROR ("self fields not writable", SCM_EOL);
0f2d19dd
JB
118 case 'r':
119 case 'o':
120 break;
2c36c351
MD
121 case 'R':
122 case 'W':
123 case 'O':
27646f41 124 if (scm_i_string_ref (fields, x) == 's')
2ade72d7
DH
125 SCM_MISC_ERROR ("self fields not allowed in tail array",
126 SCM_EOL);
127 if (x != len - 2)
128 SCM_MISC_ERROR ("tail array field must be last field in layout",
129 SCM_EOL);
2c36c351 130 break;
0f2d19dd 131 default:
2ade72d7 132 SCM_MISC_ERROR ("unrecognized ref specification: ~S",
27646f41 133 scm_list_1 (SCM_MAKE_CHAR (c)));
0f2d19dd
JB
134 }
135#if 0
27646f41 136 if (scm_i_string_ref (fields, x, 'd'))
0f2d19dd 137 {
27646f41 138 if (!scm_i_string_ref (fields, x+2, '-'))
2ade72d7 139 SCM_MISC_ERROR ("missing dash field at position ~A",
e11e83f3 140 scm_list_1 (scm_from_int (x / 2)));
0f2d19dd
JB
141 x += 2;
142 goto recheck_ref;
143 }
144#endif
145 }
cc95e00a 146 new_sym = scm_string_to_symbol (fields);
0f2d19dd 147 }
8824ac88
MV
148 scm_remember_upto_here_1 (fields);
149 return new_sym;
0f2d19dd 150}
1bbd0b84 151#undef FUNC_NAME
0f2d19dd
JB
152
153\f
aa42c036
LC
154/* Check whether VTABLE instances have a simple layout (i.e., either only "pr"
155 or only "pw" fields) and update its flags accordingly. */
156static void
157set_vtable_layout_flags (SCM vtable)
158{
159 size_t len, field;
160 SCM layout;
161 const char *c_layout;
162 scm_t_bits flags = SCM_VTABLE_FLAG_SIMPLE;
163
164 layout = SCM_VTABLE_LAYOUT (vtable);
165 c_layout = scm_i_symbol_chars (layout);
166 len = scm_i_symbol_length (layout);
167
168 assert (len % 2 == 0);
169
170 /* Update FLAGS according to LAYOUT. */
171 for (field = 0;
172 field < len && flags & SCM_VTABLE_FLAG_SIMPLE;
173 field += 2)
174 {
175 if (c_layout[field] != 'p')
176 flags = 0;
177 else
178 switch (c_layout[field + 1])
179 {
180 case 'w':
181 case 'W':
e03b7f73 182 if (field == 0)
aa42c036
LC
183 flags |= SCM_VTABLE_FLAG_SIMPLE_RW;
184 break;
185
186 case 'r':
187 case 'R':
e03b7f73 188 flags &= ~SCM_VTABLE_FLAG_SIMPLE_RW;
aa42c036
LC
189 break;
190
191 default:
192 flags = 0;
193 }
194 }
195
196 if (flags & SCM_VTABLE_FLAG_SIMPLE)
197 {
198 /* VTABLE is simple so update its flags and record the size of its
199 instances. */
200 SCM_SET_VTABLE_FLAGS (vtable, flags);
201 SCM_STRUCT_DATA_SET (vtable, scm_vtable_index_size, len / 2);
202 }
203}
0f2d19dd 204
631237b4
AW
205static int
206scm_is_valid_vtable_layout (SCM layout)
207{
208 size_t len, n;
209 const char *c_layout;
210
211 c_layout = scm_i_symbol_chars (layout);
212 len = scm_i_symbol_length (layout);
213
214 if (len % 2)
215 return 0;
216
217 for (n = 0; n < len; n += 2)
218 switch (c_layout[n])
219 {
220 case 'u':
221 case 'p':
222 case 's':
223 switch (c_layout[n+1])
224 {
225 case 'W':
226 case 'R':
227 case 'O':
228 if (n + 2 != len)
229 return 0;
230 case 'w':
231 case 'h':
232 case 'r':
233 case 'o':
234 break;
235 default:
236 return 0;
237 }
238 break;
239 default:
240 return 0;
241 }
242 return 1;
243}
244
696ac4df
LC
245/* Have OBJ, a newly created vtable, inherit flags from VTABLE. VTABLE is a
246 vtable-vtable and OBJ is an instance of VTABLE. */
51f66c91
AW
247void
248scm_i_struct_inherit_vtable_magic (SCM vtable, SCM obj)
249#define FUNC_NAME "%inherit-vtable-magic"
250{
251 /* Verily, what is the deal here, you ask? Basically, we need to know a couple
252 of properties of structures at runtime. For example, "is this structure a
253 vtable of vtables (a metaclass)?"; also, "is this structure applicable?".
254 Both of these questions also imply a certain layout of the structure. So
255 instead of checking the layout at runtime, what we do is pre-verify the
256 layout -- so that at runtime we can just check the applicable flag and
696ac4df 257 dispatch directly to the Scheme procedure in slot 0. */
51f66c91
AW
258 SCM olayout;
259
696ac4df 260 /* Verify that OBJ is a valid vtable. */
631237b4 261 if (! scm_is_valid_vtable_layout (SCM_VTABLE_LAYOUT (obj)))
a2220d7e 262 SCM_MISC_ERROR ("invalid layout for new vtable: ~a",
51f66c91
AW
263 scm_list_1 (SCM_VTABLE_LAYOUT (obj)));
264
aa42c036
LC
265 set_vtable_layout_flags (obj);
266
696ac4df
LC
267 /* If OBJ's vtable is compatible with the required vtable (class) layout, it
268 is a metaclass. */
51f66c91
AW
269 olayout = scm_symbol_to_string (SCM_VTABLE_LAYOUT (obj));
270 if (scm_is_true (scm_leq_p (scm_string_length (required_vtable_fields),
271 scm_string_length (olayout)))
272 && scm_is_true (scm_string_eq (olayout, required_vtable_fields,
273 scm_from_size_t (0),
274 scm_string_length (required_vtable_fields),
275 scm_from_size_t (0),
276 scm_string_length (required_vtable_fields))))
277 SCM_SET_VTABLE_FLAGS (obj, SCM_VTABLE_FLAG_VTABLE);
278
696ac4df
LC
279 /* Finally, if OBJ is an applicable class, verify that its vtable is
280 compatible with the required applicable layout. */
51f66c91
AW
281 if (SCM_VTABLE_FLAG_IS_SET (vtable, SCM_VTABLE_FLAG_SETTER_VTABLE))
282 {
283 if (scm_is_false (scm_string_eq (olayout, required_applicable_with_setter_fields,
284 scm_from_size_t (0),
285 scm_from_size_t (4),
286 scm_from_size_t (0),
287 scm_from_size_t (4))))
a2220d7e 288 SCM_MISC_ERROR ("invalid applicable-with-setter struct layout",
51f66c91
AW
289 scm_list_1 (olayout));
290 SCM_SET_VTABLE_FLAGS (obj, SCM_VTABLE_FLAG_APPLICABLE | SCM_VTABLE_FLAG_SETTER);
291 }
292 else if (SCM_VTABLE_FLAG_IS_SET (vtable, SCM_VTABLE_FLAG_APPLICABLE_VTABLE))
293 {
294 if (scm_is_false (scm_string_eq (olayout, required_applicable_fields,
295 scm_from_size_t (0),
296 scm_from_size_t (2),
297 scm_from_size_t (0),
298 scm_from_size_t (2))))
a2220d7e 299 SCM_MISC_ERROR ("invalid applicable struct layout",
51f66c91
AW
300 scm_list_1 (olayout));
301 SCM_SET_VTABLE_FLAGS (obj, SCM_VTABLE_FLAG_APPLICABLE);
302 }
a2220d7e
AW
303
304 SCM_SET_VTABLE_FLAGS (obj, SCM_VTABLE_FLAG_VALIDATED);
51f66c91
AW
305}
306#undef FUNC_NAME
0f2d19dd 307
1cc91f1b 308
f7620510 309static void
66e78727
AW
310scm_struct_init (SCM handle, SCM layout, size_t n_tail,
311 size_t n_inits, scm_t_bits *inits)
0f2d19dd 312{
aa42c036
LC
313 SCM vtable;
314 scm_t_bits *mem;
315
316 vtable = SCM_STRUCT_VTABLE (handle);
317 mem = SCM_STRUCT_DATA (handle);
318
319 if (SCM_UNPACK (vtable) != 0
320 && SCM_VTABLE_FLAG_IS_SET (vtable, SCM_VTABLE_FLAG_SIMPLE)
321 && n_tail == 0
322 && n_inits == SCM_STRUCT_DATA_REF (vtable, scm_vtable_index_size))
323 /* The fast path: HANDLE has N_INITS "p" fields. */
324 memcpy (mem, inits, n_inits * sizeof (SCM));
325 else
0f2d19dd 326 {
aa42c036
LC
327 scm_t_wchar prot = 0;
328 int n_fields = scm_i_symbol_length (layout) / 2;
329 int tailp = 0;
330 int i;
331 size_t inits_idx = 0;
332
333 i = -2;
334 while (n_fields)
2c36c351 335 {
aa42c036 336 if (!tailp)
2c36c351 337 {
aa42c036
LC
338 i += 2;
339 prot = scm_i_symbol_ref (layout, i+1);
340 if (SCM_LAYOUT_TAILP (prot))
341 {
342 tailp = 1;
343 prot = prot == 'R' ? 'r' : prot == 'W' ? 'w' : 'o';
344 *mem++ = (scm_t_bits)n_tail;
345 n_fields += n_tail - 1;
346 if (n_fields == 0)
347 break;
348 }
2c36c351 349 }
aa42c036 350 switch (scm_i_symbol_ref (layout, i))
0f2d19dd 351 {
aa42c036
LC
352 case 'u':
353 if ((prot != 'r' && prot != 'w') || inits_idx == n_inits)
354 *mem = 0;
355 else
356 {
357 *mem = scm_to_ulong (SCM_PACK (inits[inits_idx]));
358 inits_idx++;
359 }
360 break;
361
362 case 'p':
363 if ((prot != 'r' && prot != 'w') || inits_idx == n_inits)
364 *mem = SCM_UNPACK (SCM_BOOL_F);
365 else
366 {
367 *mem = inits[inits_idx];
368 inits_idx++;
369 }
370
371 break;
372
373 case 's':
374 *mem = SCM_UNPACK (handle);
375 break;
0f2d19dd 376 }
0f2d19dd 377
aa42c036
LC
378 n_fields--;
379 mem++;
0f2d19dd 380 }
0f2d19dd
JB
381 }
382}
383
384
a1ec6916 385SCM_DEFINE (scm_struct_p, "struct?", 1, 0, 0,
1bbd0b84 386 (SCM x),
0233bfc1 387 "Return @code{#t} iff @var{x} is a structure object, else\n"
942e5b91 388 "@code{#f}.")
1bbd0b84 389#define FUNC_NAME s_scm_struct_p
0f2d19dd 390{
7888309b 391 return scm_from_bool(SCM_STRUCTP (x));
0f2d19dd 392}
1bbd0b84 393#undef FUNC_NAME
0f2d19dd 394
a1ec6916 395SCM_DEFINE (scm_struct_vtable_p, "struct-vtable?", 1, 0, 0,
1bbd0b84 396 (SCM x),
0233bfc1 397 "Return @code{#t} iff @var{x} is a vtable structure.")
1bbd0b84 398#define FUNC_NAME s_scm_struct_vtable_p
0f2d19dd 399{
a2220d7e
AW
400 if (!SCM_STRUCTP (x)
401 || !SCM_STRUCT_VTABLE_FLAG_IS_SET (x, SCM_VTABLE_FLAG_VTABLE))
402 return SCM_BOOL_F;
403 if (!SCM_VTABLE_FLAG_IS_SET (x, SCM_VTABLE_FLAG_VALIDATED))
404 SCM_MISC_ERROR ("vtable has invalid layout: ~A",
405 scm_list_1 (SCM_VTABLE_LAYOUT (x)));
406 return SCM_BOOL_T;
0f2d19dd 407}
1bbd0b84 408#undef FUNC_NAME
0f2d19dd 409
14d1400f 410
51f66c91
AW
411/* Finalization: invoke the finalizer of the struct pointed to by PTR. */
412static void
413struct_finalizer_trampoline (GC_PTR ptr, GC_PTR unused_data)
414{
415 SCM obj = PTR2SCM (ptr);
416 scm_t_struct_finalize finalize = SCM_STRUCT_FINALIZER (obj);
417
418 if (finalize)
419 finalize (obj);
420}
421
14d1400f
JB
422/* All struct data must be allocated at an address whose bottom three
423 bits are zero. This is because the tag for a struct lives in the
424 bottom three bits of the struct's car, and the upper bits point to
425 the data of its vtable, which is a struct itself. Thus, if the
426 address of that data doesn't end in three zeros, tagging it will
427 destroy the pointer.
428
b6cf4d02
AW
429 I suppose we should make it clear here that, the data must be 8-byte aligned,
430 *within* the struct, and the struct itself should be 8-byte aligned. In
431 practice we ensure this because the data starts two words into a struct.
14d1400f 432
b6cf4d02
AW
433 This function allocates an 8-byte aligned block of memory, whose first word
434 points to the given vtable data, then a data pointer, then n_words of data.
435 */
436SCM
96a44c1c 437scm_i_alloc_struct (scm_t_bits *vtable_data, int n_words)
14d1400f 438{
9a974fd3
AW
439 SCM ret;
440
441 ret = scm_words ((scm_t_bits)vtable_data | scm_tc3_struct, n_words + 2);
442 SCM_SET_CELL_WORD_1 (ret, (scm_t_bits)SCM_CELL_OBJECT_LOC (ret, 2));
5e67dc27 443
51f66c91
AW
444 /* vtable_data can be null when making a vtable vtable */
445 if (vtable_data && vtable_data[scm_vtable_index_instance_finalize])
75ba64d6
AW
446 /* Register a finalizer for the newly created instance. */
447 scm_i_set_finalizer (SCM2PTR (ret), struct_finalizer_trampoline, NULL);
5e67dc27 448
9a974fd3 449 return ret;
5e67dc27
LC
450}
451
5e67dc27 452\f
66e78727
AW
453SCM
454scm_c_make_structv (SCM vtable, size_t n_tail, size_t n_init, scm_t_bits *init)
455#define FUNC_NAME "make-struct"
0f2d19dd
JB
456{
457 SCM layout;
a55c2b68 458 size_t basic_size;
b6cf4d02 459 SCM obj;
0f2d19dd 460
34d19ef6 461 SCM_VALIDATE_VTABLE (1, vtable);
0f2d19dd 462
b6cf4d02 463 layout = SCM_VTABLE_LAYOUT (vtable);
cc95e00a 464 basic_size = scm_i_symbol_length (layout) / 2;
651f2cd2 465
66e78727 466 if (n_tail != 0)
651f2cd2
KR
467 {
468 SCM layout_str, last_char;
469
470 if (basic_size == 0)
471 {
472 bad_tail:
473 SCM_MISC_ERROR ("tail array not allowed unless layout ends R, W, or O", SCM_EOL);
474 }
475
476 layout_str = scm_symbol_to_string (layout);
477 last_char = scm_string_ref (layout_str,
478 scm_from_size_t (2 * basic_size - 1));
479 if (! SCM_LAYOUT_TAILP (SCM_CHAR (last_char)))
480 goto bad_tail;
481 }
cb823e63 482
96a44c1c 483 obj = scm_i_alloc_struct (SCM_STRUCT_DATA (vtable), basic_size + n_tail);
5e67dc27 484
66e78727 485 scm_struct_init (obj, layout, n_tail, n_init, init);
b6cf4d02 486
a2220d7e
AW
487 /* If we're making a vtable, validate its layout and inherit
488 flags. However we allow for separation of allocation and
489 initialization, to humor GOOPS, so only validate if the layout was
490 passed as an initarg. */
b6cf4d02 491 if (SCM_VTABLE_FLAG_IS_SET (vtable, SCM_VTABLE_FLAG_VTABLE)
b6cf4d02 492 && scm_is_true (SCM_VTABLE_LAYOUT (obj)))
51f66c91 493 scm_i_struct_inherit_vtable_magic (vtable, obj);
651f2cd2 494
b6cf4d02 495 return obj;
0f2d19dd 496}
1bbd0b84 497#undef FUNC_NAME
0f2d19dd 498
66e78727
AW
499SCM
500scm_c_make_struct (SCM vtable, size_t n_tail, size_t n_init, scm_t_bits init, ...)
501{
502 va_list foo;
503 scm_t_bits *v;
504 size_t i;
505
506 v = alloca (sizeof (scm_t_bits) * n_init);
507
508 va_start (foo, init);
509 for (i = 0; i < n_init; i++)
510 {
511 v[i] = init;
512 init = va_arg (foo, scm_t_bits);
513 }
514 va_end (foo);
515
516 return scm_c_make_structv (vtable, n_tail, n_init, v);
517}
518
519SCM_DEFINE (scm_make_struct, "make-struct", 2, 0, 1,
520 (SCM vtable, SCM tail_array_size, SCM init),
521 "Create a new structure.\n\n"
b7e64f8b
BT
522 "@var{vtable} must be a vtable structure (@pxref{Vtables}).\n\n"
523 "@var{tail_array_size} must be a non-negative integer. If the layout\n"
524 "specification indicated by @var{vtable} includes a tail-array,\n"
66e78727
AW
525 "this is the number of elements allocated to that array.\n\n"
526 "The @var{init1}, @dots{} are optional arguments describing how\n"
527 "successive fields of the structure should be initialized. Only fields\n"
528 "with protection 'r' or 'w' can be initialized, except for fields of\n"
529 "type 's', which are automatically initialized to point to the new\n"
530 "structure itself. Fields with protection 'o' can not be initialized by\n"
531 "Scheme programs.\n\n"
532 "If fewer optional arguments than initializable fields are supplied,\n"
533 "fields of type 'p' get default value #f while fields of type 'u' are\n"
534 "initialized to 0.\n\n"
535 "For more information, see the documentation for @code{make-vtable-vtable}.")
536#define FUNC_NAME s_scm_make_struct
537{
538 size_t i, n_init;
539 long ilen;
540 scm_t_bits *v;
541
542 SCM_VALIDATE_VTABLE (1, vtable);
543 ilen = scm_ilength (init);
544 if (ilen < 0)
545 SCM_MISC_ERROR ("Rest arguments do not form a proper list.", SCM_EOL);
546
547 n_init = (size_t)ilen;
548
549 /* best to use alloca, but init could be big, so hack to avoid a possible
550 stack overflow */
551 if (n_init < 64)
552 v = alloca (n_init * sizeof(scm_t_bits));
553 else
554 v = scm_gc_malloc (n_init * sizeof(scm_t_bits), "struct");
555
556 for (i = 0; i < n_init; i++, init = SCM_CDR (init))
557 v[i] = SCM_UNPACK (SCM_CAR (init));
558
559 return scm_c_make_structv (vtable, scm_to_size_t (tail_array_size), n_init, v);
560}
561#undef FUNC_NAME
562
0f2d19dd
JB
563
564
a1ec6916 565SCM_DEFINE (scm_make_vtable_vtable, "make-vtable-vtable", 2, 0, 1,
04323af4 566 (SCM user_fields, SCM tail_array_size, SCM init),
b380b885 567 "Return a new, self-describing vtable structure.\n\n"
04323af4
MD
568 "@var{user-fields} is a string describing user defined fields of the\n"
569 "vtable beginning at index @code{vtable-offset-user}\n"
570 "(see @code{make-struct-layout}).\n\n"
b7e64f8b 571 "@var{tail_array_size} specifies the size of the tail-array (if any) of\n"
b380b885 572 "this vtable.\n\n"
6386e25c 573 "@var{init1}, @dots{} are the optional initializers for the fields of\n"
04323af4
MD
574 "the vtable.\n\n"
575 "Vtables have one initializable system field---the struct printer.\n"
576 "This field comes before the user fields in the initializers passed\n"
577 "to @code{make-vtable-vtable} and @code{make-struct}, and thus works as\n"
578 "a third optional argument to @code{make-vtable-vtable} and a fourth to\n"
579 "@code{make-struct} when creating vtables:\n\n"
580 "If the value is a procedure, it will be called instead of the standard\n"
581 "printer whenever a struct described by this vtable is printed.\n"
582 "The procedure will be called with arguments STRUCT and PORT.\n\n"
583 "The structure of a struct is described by a vtable, so the vtable is\n"
584 "in essence the type of the struct. The vtable is itself a struct with\n"
585 "a vtable. This could go on forever if it weren't for the\n"
29b4f9fb 586 "vtable-vtables which are self-describing vtables, and thus terminate\n"
04323af4
MD
587 "the chain.\n\n"
588 "There are several potential ways of using structs, but the standard\n"
589 "one is to use three kinds of structs, together building up a type\n"
590 "sub-system: one vtable-vtable working as the root and one or several\n"
591 "\"types\", each with a set of \"instances\". (The vtable-vtable should be\n"
29b4f9fb 592 "compared to the class <class> which is the class of itself.)\n\n"
1e6808ea 593 "@lisp\n"
04323af4
MD
594 "(define ball-root (make-vtable-vtable \"pr\" 0))\n\n"
595 "(define (make-ball-type ball-color)\n"
596 " (make-struct ball-root 0\n"
597 " (make-struct-layout \"pw\")\n"
598 " (lambda (ball port)\n"
599 " (format port \"#<a ~A ball owned by ~A>\"\n"
600 " (color ball)\n"
601 " (owner ball)))\n"
602 " ball-color))\n"
603 "(define (color ball) (struct-ref (struct-vtable ball) vtable-offset-user))\n"
604 "(define (owner ball) (struct-ref ball 0))\n\n"
605 "(define red (make-ball-type 'red))\n"
606 "(define green (make-ball-type 'green))\n\n"
607 "(define (make-ball type owner) (make-struct type 0 owner))\n\n"
608 "(define ball (make-ball green 'Nisse))\n"
609 "ball @result{} #<a green ball owned by Nisse>\n"
9401323e 610 "@end lisp")
1bbd0b84 611#define FUNC_NAME s_scm_make_vtable_vtable
0f2d19dd 612{
696ac4df
LC
613 SCM fields, layout, obj;
614 size_t basic_size, n_tail, i, n_init;
66e78727
AW
615 long ilen;
616 scm_t_bits *v;
0f2d19dd 617
d1ca2c64 618 SCM_VALIDATE_STRING (1, user_fields);
66e78727
AW
619 ilen = scm_ilength (init);
620 if (ilen < 0)
621 SCM_MISC_ERROR ("Rest arguments do not form a proper list.", SCM_EOL);
622
623 n_init = (size_t)ilen + 1; /* + 1 for the layout */
624
625 /* best to use alloca, but init could be big, so hack to avoid a possible
626 stack overflow */
627 if (n_init < 64)
628 v = alloca (n_init * sizeof(scm_t_bits));
629 else
630 v = scm_gc_malloc (n_init * sizeof(scm_t_bits), "struct");
0f2d19dd 631
1afff620
KN
632 fields = scm_string_append (scm_list_2 (required_vtable_fields,
633 user_fields));
0f2d19dd 634 layout = scm_make_struct_layout (fields);
a2220d7e
AW
635 if (!scm_is_valid_vtable_layout (layout))
636 SCM_MISC_ERROR ("invalid user fields", scm_list_1 (user_fields));
637
cc95e00a 638 basic_size = scm_i_symbol_length (layout) / 2;
66e78727
AW
639 n_tail = scm_to_size_t (tail_array_size);
640
641 i = 0;
642 v[i++] = SCM_UNPACK (layout);
643 for (; i < n_init; i++, init = SCM_CDR (init))
644 v[i] = SCM_UNPACK (SCM_CAR (init));
645
9de87eea 646 SCM_CRITICAL_SECTION_START;
96a44c1c 647 obj = scm_i_alloc_struct (NULL, basic_size + n_tail);
696ac4df
LC
648 /* Make it so that the vtable of OBJ is itself. */
649 SCM_SET_CELL_WORD_0 (obj, (scm_t_bits) SCM_STRUCT_DATA (obj) | scm_tc3_struct);
9de87eea 650 SCM_CRITICAL_SECTION_END;
696ac4df 651
66e78727 652 scm_struct_init (obj, layout, n_tail, n_init, v);
a2220d7e
AW
653 SCM_SET_VTABLE_FLAGS (obj,
654 SCM_VTABLE_FLAG_VTABLE | SCM_VTABLE_FLAG_VALIDATED);
696ac4df 655
b6cf4d02 656 return obj;
0f2d19dd 657}
1bbd0b84 658#undef FUNC_NAME
0f2d19dd 659
d15ad007 660
651f2cd2
KR
661SCM_DEFINE (scm_make_vtable, "make-vtable", 1, 1, 0,
662 (SCM fields, SCM printer),
663 "Create a vtable, for creating structures with the given\n"
664 "@var{fields}.\n"
665 "\n"
666 "The optional @var{printer} argument is a function to be called\n"
667 "@code{(@var{printer} struct port)} on the structures created.\n"
668 "It should look at @var{struct} and write to @var{port}.")
669#define FUNC_NAME s_scm_make_vtable
670{
671 if (SCM_UNBNDP (printer))
672 printer = SCM_BOOL_F;
673
db5ed685 674 return scm_make_struct (scm_standard_vtable_vtable, SCM_INUM0,
651f2cd2
KR
675 scm_list_2 (scm_make_struct_layout (fields),
676 printer));
677}
678#undef FUNC_NAME
679
680
d15ad007
LC
681/* Return true if S1 and S2 are equal structures, i.e., if their vtable and
682 contents are the same. Field protections are honored. Thus, it is an
683 error to test the equality of structures that contain opaque fields. */
684SCM
685scm_i_struct_equalp (SCM s1, SCM s2)
686#define FUNC_NAME "scm_i_struct_equalp"
687{
688 SCM vtable1, vtable2, layout;
689 size_t struct_size, field_num;
690
691 SCM_VALIDATE_STRUCT (1, s1);
692 SCM_VALIDATE_STRUCT (2, s2);
693
694 vtable1 = SCM_STRUCT_VTABLE (s1);
695 vtable2 = SCM_STRUCT_VTABLE (s2);
696
697 if (!scm_is_eq (vtable1, vtable2))
698 return SCM_BOOL_F;
699
700 layout = SCM_STRUCT_LAYOUT (s1);
701 struct_size = scm_i_symbol_length (layout) / 2;
702
703 for (field_num = 0; field_num < struct_size; field_num++)
704 {
705 SCM s_field_num;
706 SCM field1, field2;
707
708 /* We have to use `scm_struct_ref ()' here so that fields are accessed
709 consistently, notably wrt. field types and access rights. */
710 s_field_num = scm_from_size_t (field_num);
711 field1 = scm_struct_ref (s1, s_field_num);
712 field2 = scm_struct_ref (s2, s_field_num);
713
42ddb3cb
LC
714 /* Self-referencing fields (type `s') must be skipped to avoid infinite
715 recursion. */
716 if (!(scm_is_eq (field1, s1) && (scm_is_eq (field2, s2))))
717 if (scm_is_false (scm_equal_p (field1, field2)))
718 return SCM_BOOL_F;
d15ad007
LC
719 }
720
42ddb3cb
LC
721 /* FIXME: Tail elements should be tested for equality. */
722
d15ad007
LC
723 return SCM_BOOL_T;
724}
725#undef FUNC_NAME
726
727
0f2d19dd
JB
728\f
729
730
a1ec6916 731SCM_DEFINE (scm_struct_ref, "struct-ref", 2, 0, 0,
1bbd0b84 732 (SCM handle, SCM pos),
b7e64f8b
BT
733 "Access the @var{pos}th field of struct associated with\n"
734 "@var{handle}.\n"
735 "\n"
736 "If the field is of type 'p', then it can be set to an arbitrary\n"
737 "value.\n"
738 "\n"
739 "If the field is of type 'u', then it can only be set to a\n"
740 "non-negative integer value small enough to fit in one machine\n"
741 "word.")
1bbd0b84 742#define FUNC_NAME s_scm_struct_ref
0f2d19dd 743{
aa42c036
LC
744 SCM vtable, answer = SCM_UNDEFINED;
745 scm_t_bits *data;
a55c2b68 746 size_t p;
0f2d19dd 747
34d19ef6 748 SCM_VALIDATE_STRUCT (1, handle);
0f2d19dd 749
aa42c036 750 vtable = SCM_STRUCT_VTABLE (handle);
0f2d19dd 751 data = SCM_STRUCT_DATA (handle);
a55c2b68 752 p = scm_to_size_t (pos);
0f2d19dd 753
aa42c036
LC
754 if (SCM_LIKELY (SCM_VTABLE_FLAG_IS_SET (vtable, SCM_VTABLE_FLAG_SIMPLE)
755 && p < SCM_STRUCT_DATA_REF (vtable, scm_vtable_index_size)))
e03b7f73
LC
756 /* The fast path: HANDLE is a struct with only "p" fields. */
757 answer = SCM_PACK (data[p]);
2c36c351 758 else
0f2d19dd 759 {
aa42c036
LC
760 SCM layout;
761 size_t layout_len, n_fields;
762 scm_t_wchar field_type = 0;
763
764 layout = SCM_STRUCT_LAYOUT (handle);
765 layout_len = scm_i_symbol_length (layout);
766 n_fields = layout_len / 2;
767
768 if (SCM_LAYOUT_TAILP (scm_i_symbol_ref (layout, layout_len - 1)))
769 n_fields += data[n_fields - 1];
770
771 SCM_ASSERT_RANGE (1, pos, p < n_fields);
772
773 if (p * 2 < layout_len)
774 {
775 scm_t_wchar ref;
776 field_type = scm_i_symbol_ref (layout, p * 2);
777 ref = scm_i_symbol_ref (layout, p * 2 + 1);
778 if ((ref != 'r') && (ref != 'w') && (ref != 'h'))
779 {
780 if ((ref == 'R') || (ref == 'W'))
781 field_type = 'u';
782 else
783 SCM_MISC_ERROR ("ref denied for field ~A", scm_list_1 (pos));
784 }
785 }
786 else if (scm_i_symbol_ref (layout, layout_len - 1) != 'O')
787 field_type = scm_i_symbol_ref(layout, layout_len - 2);
788 else
789 SCM_MISC_ERROR ("ref denied for field ~A", scm_list_1 (pos));
790
791 switch (field_type)
792 {
793 case 'u':
794 answer = scm_from_ulong (data[p]);
795 break;
0f2d19dd
JB
796
797#if 0
aa42c036
LC
798 case 'i':
799 answer = scm_from_long (data[p]);
800 break;
0f2d19dd 801
aa42c036
LC
802 case 'd':
803 answer = scm_make_real (*((double *)&(data[p])));
804 break;
0f2d19dd
JB
805#endif
806
aa42c036
LC
807 case 's':
808 case 'p':
809 answer = SCM_PACK (data[p]);
810 break;
0f2d19dd
JB
811
812
aa42c036
LC
813 default:
814 SCM_MISC_ERROR ("unrecognized field type: ~S",
815 scm_list_1 (SCM_MAKE_CHAR (field_type)));
816 }
0f2d19dd
JB
817 }
818
819 return answer;
820}
1bbd0b84 821#undef FUNC_NAME
0f2d19dd
JB
822
823
a1ec6916 824SCM_DEFINE (scm_struct_set_x, "struct-set!", 3, 0, 0,
1bbd0b84 825 (SCM handle, SCM pos, SCM val),
e3239868
DH
826 "Set the slot of the structure @var{handle} with index @var{pos}\n"
827 "to @var{val}. Signal an error if the slot can not be written\n"
828 "to.")
1bbd0b84 829#define FUNC_NAME s_scm_struct_set_x
0f2d19dd 830{
aa42c036
LC
831 SCM vtable;
832 scm_t_bits *data;
a55c2b68 833 size_t p;
0f2d19dd 834
34d19ef6 835 SCM_VALIDATE_STRUCT (1, handle);
0f2d19dd 836
aa42c036 837 vtable = SCM_STRUCT_VTABLE (handle);
0f2d19dd 838 data = SCM_STRUCT_DATA (handle);
a55c2b68 839 p = scm_to_size_t (pos);
0f2d19dd 840
aa42c036
LC
841 if (SCM_LIKELY (SCM_VTABLE_FLAG_IS_SET (vtable, SCM_VTABLE_FLAG_SIMPLE)
842 && SCM_VTABLE_FLAG_IS_SET (vtable, SCM_VTABLE_FLAG_SIMPLE_RW)
843 && p < SCM_STRUCT_DATA_REF (vtable, scm_vtable_index_size)))
e03b7f73 844 /* The fast path: HANDLE is a struct with only "pw" fields. */
aa42c036
LC
845 data[p] = SCM_UNPACK (val);
846 else
847 {
848 SCM layout;
849 size_t layout_len, n_fields;
850 scm_t_wchar field_type = 0;
0f2d19dd 851
aa42c036
LC
852 layout = SCM_STRUCT_LAYOUT (handle);
853 layout_len = scm_i_symbol_length (layout);
854 n_fields = layout_len / 2;
0f2d19dd 855
aa42c036
LC
856 if (SCM_LAYOUT_TAILP (scm_i_symbol_ref (layout, layout_len - 1)))
857 n_fields += data[n_fields - 1];
858
859 SCM_ASSERT_RANGE (1, pos, p < n_fields);
860
861 if (p * 2 < layout_len)
862 {
863 char set_x;
864 field_type = scm_i_symbol_ref (layout, p * 2);
865 set_x = scm_i_symbol_ref (layout, p * 2 + 1);
866 if (set_x != 'w' && set_x != 'h')
867 SCM_MISC_ERROR ("set! denied for field ~A", scm_list_1 (pos));
868 }
869 else if (scm_i_symbol_ref (layout, layout_len - 1) == 'W')
870 field_type = scm_i_symbol_ref (layout, layout_len - 2);
871 else
1afff620 872 SCM_MISC_ERROR ("set! denied for field ~A", scm_list_1 (pos));
aa42c036
LC
873
874 switch (field_type)
875 {
876 case 'u':
877 data[p] = SCM_NUM2ULONG (3, val);
878 break;
0f2d19dd
JB
879
880#if 0
aa42c036
LC
881 case 'i':
882 data[p] = SCM_NUM2LONG (3, val);
883 break;
0f2d19dd 884
aa42c036
LC
885 case 'd':
886 *((double *)&(data[p])) = scm_num2dbl (val, (char *)SCM_ARG3);
887 break;
0f2d19dd
JB
888#endif
889
aa42c036
LC
890 case 'p':
891 data[p] = SCM_UNPACK (val);
892 break;
0f2d19dd 893
aa42c036
LC
894 case 's':
895 SCM_MISC_ERROR ("self fields immutable", SCM_EOL);
0f2d19dd 896
aa42c036
LC
897 default:
898 SCM_MISC_ERROR ("unrecognized field type: ~S",
899 scm_list_1 (SCM_MAKE_CHAR (field_type)));
900 }
0f2d19dd
JB
901 }
902
903 return val;
904}
1bbd0b84 905#undef FUNC_NAME
0f2d19dd
JB
906
907
a1ec6916 908SCM_DEFINE (scm_struct_vtable, "struct-vtable", 1, 0, 0,
1bbd0b84 909 (SCM handle),
b7e64f8b
BT
910 "Return the vtable structure that describes the type of struct\n"
911 "associated with @var{handle}.")
1bbd0b84 912#define FUNC_NAME s_scm_struct_vtable
0f2d19dd 913{
34d19ef6 914 SCM_VALIDATE_STRUCT (1, handle);
0f2d19dd
JB
915 return SCM_STRUCT_VTABLE (handle);
916}
1bbd0b84 917#undef FUNC_NAME
0f2d19dd
JB
918
919
a1ec6916 920SCM_DEFINE (scm_struct_vtable_tag, "struct-vtable-tag", 1, 0, 0,
1bbd0b84 921 (SCM handle),
e3239868 922 "Return the vtable tag of the structure @var{handle}.")
1bbd0b84 923#define FUNC_NAME s_scm_struct_vtable_tag
0f2d19dd 924{
34d19ef6 925 SCM_VALIDATE_VTABLE (1, handle);
3d27ef4b
AW
926 return scm_from_unsigned_integer
927 (((scm_t_bits)SCM_STRUCT_DATA (handle)) >> 3);
98d5f601 928}
1bbd0b84 929#undef FUNC_NAME
98d5f601
MD
930
931/* {Associating names and classes with vtables}
932 *
933 * The name of a vtable should probably be stored as a slot. This is
934 * a backward compatible solution until agreement has been achieved on
935 * how to associate names with vtables.
936 */
937
c014a02e 938unsigned long
d587c9e8 939scm_struct_ihashq (SCM obj, unsigned long n, void *closure)
98d5f601 940{
ad196599
MD
941 /* The length of the hash table should be a relative prime it's not
942 necessary to shift down the address. */
f1267706 943 return SCM_UNPACK (obj) % n;
98d5f601
MD
944}
945
a1ec6916 946SCM_DEFINE (scm_struct_vtable_name, "struct-vtable-name", 1, 0, 0,
1bbd0b84 947 (SCM vtable),
e3239868 948 "Return the name of the vtable @var{vtable}.")
1bbd0b84 949#define FUNC_NAME s_scm_struct_vtable_name
98d5f601 950{
34d19ef6 951 SCM_VALIDATE_VTABLE (1, vtable);
f3c6a02c 952 return SCM_VTABLE_NAME (vtable);
98d5f601 953}
1bbd0b84 954#undef FUNC_NAME
98d5f601 955
a1ec6916 956SCM_DEFINE (scm_set_struct_vtable_name_x, "set-struct-vtable-name!", 2, 0, 0,
1bbd0b84 957 (SCM vtable, SCM name),
e3239868 958 "Set the name of the vtable @var{vtable} to @var{name}.")
1bbd0b84 959#define FUNC_NAME s_scm_set_struct_vtable_name_x
98d5f601 960{
34d19ef6
HWN
961 SCM_VALIDATE_VTABLE (1, vtable);
962 SCM_VALIDATE_SYMBOL (2, name);
f3c6a02c
AW
963 SCM_SET_VTABLE_NAME (vtable, name);
964 /* FIXME: remove this, and implement proper struct classes instead.
965 (Vtables *are* classes.) */
966 scm_i_define_class_for_vtable (vtable);
98d5f601 967 return SCM_UNSPECIFIED;
0f2d19dd 968}
1bbd0b84 969#undef FUNC_NAME
0f2d19dd
JB
970
971
972\f
973
bafcafb2 974void
1bbd0b84 975scm_print_struct (SCM exp, SCM port, scm_print_state *pstate)
bafcafb2 976{
7888309b 977 if (scm_is_true (scm_procedure_p (SCM_STRUCT_PRINTER (exp))))
4bfdf158
MD
978 scm_printer_apply (SCM_STRUCT_PRINTER (exp), exp, port, pstate);
979 else
bafcafb2 980 {
a1ae1799
MD
981 SCM vtable = SCM_STRUCT_VTABLE (exp);
982 SCM name = scm_struct_vtable_name (vtable);
983 scm_puts ("#<", port);
7888309b 984 if (scm_is_true (name))
b6cf4d02
AW
985 {
986 scm_display (name, port);
987 scm_putc (' ', port);
988 }
a1ae1799 989 else
b6cf4d02
AW
990 {
991 if (SCM_VTABLE_FLAG_IS_SET (vtable, SCM_VTABLE_FLAG_VTABLE))
992 scm_puts ("vtable:", port);
993 else
994 scm_puts ("struct:", port);
995 scm_uintprint (SCM_UNPACK (vtable), 16, port);
996 scm_putc (' ', port);
997 scm_write (SCM_VTABLE_LAYOUT (vtable), port);
998 scm_putc (' ', port);
999 }
0345e278 1000 scm_uintprint (SCM_UNPACK (exp), 16, port);
b6cf4d02
AW
1001 /* hackety hack */
1002 if (SCM_STRUCT_APPLICABLE_P (exp))
1003 {
1004 if (scm_is_true (SCM_STRUCT_PROCEDURE (exp)))
1005 {
1006 scm_puts (" proc: ", port);
1007 if (scm_is_true (scm_procedure_p (SCM_STRUCT_PROCEDURE (exp))))
1008 scm_write (SCM_STRUCT_PROCEDURE (exp), port);
1009 else
1010 scm_puts ("(not a procedure?)", port);
1011 }
1012 if (SCM_STRUCT_SETTER_P (exp))
1013 {
1014 scm_puts (" setter: ", port);
1015 scm_write (SCM_STRUCT_SETTER (exp), port);
1016 }
1017 }
b7f3516f 1018 scm_putc ('>', port);
bafcafb2 1019 }
bafcafb2 1020}
1cc91f1b 1021
0f2d19dd
JB
1022void
1023scm_init_struct ()
0f2d19dd 1024{
01e74380
LC
1025 /* The first word of a struct is equal to `SCM_STRUCT_DATA (vtable) +
1026 scm_tc3_struct', and `SCM_STRUCT_DATA (vtable)' is 2 words after VTABLE by
1027 default. */
1028 GC_REGISTER_DISPLACEMENT (2 * sizeof (scm_t_bits) + scm_tc3_struct);
b6cf4d02 1029
227eff6a
LC
1030 /* In the general case, `SCM_STRUCT_DATA (obj)' points 2 words after the
1031 beginning of a GC-allocated region; that region is different from that of
1032 OBJ once OBJ has undergone class redefinition. */
1033 GC_REGISTER_DISPLACEMENT (2 * sizeof (scm_t_bits));
1034
b6cf4d02
AW
1035 required_vtable_fields = scm_from_locale_string (SCM_VTABLE_BASE_LAYOUT);
1036 required_applicable_fields = scm_from_locale_string (SCM_APPLICABLE_BASE_LAYOUT);
1037 required_applicable_with_setter_fields = scm_from_locale_string (SCM_APPLICABLE_WITH_SETTER_BASE_LAYOUT);
651f2cd2 1038
db5ed685 1039 scm_standard_vtable_vtable =
b6cf4d02
AW
1040 scm_make_vtable_vtable (scm_nullstr, SCM_INUM0, SCM_EOL);
1041
1042 scm_applicable_struct_vtable_vtable =
db5ed685 1043 scm_make_struct (scm_standard_vtable_vtable, SCM_INUM0,
b6cf4d02
AW
1044 scm_list_1 (scm_make_struct_layout (required_vtable_fields)));
1045 SCM_SET_VTABLE_FLAGS (scm_applicable_struct_vtable_vtable,
1046 SCM_VTABLE_FLAG_APPLICABLE_VTABLE);
1047 scm_c_define ("<applicable-struct-vtable>", scm_applicable_struct_vtable_vtable);
1048
1049 scm_applicable_struct_with_setter_vtable_vtable =
db5ed685 1050 scm_make_struct (scm_standard_vtable_vtable, SCM_INUM0,
b6cf4d02
AW
1051 scm_list_1 (scm_make_struct_layout (required_vtable_fields)));
1052 SCM_SET_VTABLE_FLAGS (scm_applicable_struct_with_setter_vtable_vtable,
1053 SCM_VTABLE_FLAG_APPLICABLE_VTABLE | SCM_VTABLE_FLAG_SETTER_VTABLE);
1054 scm_c_define ("<applicable-struct-with-setter-vtable>", scm_applicable_struct_with_setter_vtable_vtable);
651f2cd2 1055
e11e83f3 1056 scm_c_define ("vtable-index-layout", scm_from_int (scm_vtable_index_layout));
86d31dfe 1057 scm_c_define ("vtable-index-printer",
b6cf4d02 1058 scm_from_int (scm_vtable_index_instance_printer));
e11e83f3 1059 scm_c_define ("vtable-offset-user", scm_from_int (scm_vtable_offset_user));
a0599745 1060#include "libguile/struct.x"
0f2d19dd 1061}
89e00824
ML
1062
1063/*
1064 Local Variables:
1065 c-file-style: "gnu"
1066 End:
1067*/