496e9b9e47ab5df3abeae09e18017aab79a10000
[sxemacs] / src / effi.c
1 /*
2  * effi.c --- Foreign Function Interface for SXEmacs.
3  *
4  * Copyright (C) 2004-2008 Zajcev Evgeny
5  *
6 This file is part of SXEmacs
7
8 SXEmacs is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 SXEmacs is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program.  If not, see <http://www.gnu.org/licenses/>. */
20
21
22 #include <config.h>
23 #include "lisp.h"
24
25 #include <dlfcn.h>
26 #include <math.h>
27 #include "sysdep.h"
28 #include "effi.h"
29
30 #include "buffer.h"
31 #ifdef FILE_CODING
32 #  include "mule/file-coding.h"
33 #endif
34
35 #ifdef HAVE_LIBFFI
36 #  undef ALIGN
37 #  include <ffi.h>
38 #endif  /* HAVE_LIBFFI */
39
40 #ifdef EF_USE_ASYNEQ
41 #  include "events/workers.h"
42 #  include "events/worker-asyneq.h"
43 #endif  /* EF_USE_ASYNEQ */
44
45 /* For `x-device-display' */
46 #include "ui/X11/console-x.h"
47 #include "ui/device.h"
48
49 #define EFFI_CODING     Qnative
50
51 /*
52  * Some compatibility for XEmacs
53  */
54 #ifdef SXEMACS
55 #  define SIGNAL_ERROR signal_error
56 #  define FFIBYTE Bufbyte
57 #  define WRITE_C_STRING(x,y) write_c_string((x),(y))
58 #  define WRITE_FMT_STRING(x,y,...) write_fmt_string((x),(y),__VA_ARGS__)
59 #  define LRECORD_DESCRIPTION lrecord_description
60 #else
61 #  define SIGNAL_ERROR Fsignal
62 #  define FFIBYTE Ibyte
63 #  define WRITE_C_STRING(x,y) write_c_string((y),(x))
64 #  define WRITE_FMT_STRING(x,y,...)                     \
65         do {                                            \
66                 char wcsb[128];                         \
67                 int wcss = snprintf(wcsb, sizeof(wcsb), \
68                                     (y),__VA_ARGS__);   \
69                 write_c_string((y),wcsb);               \
70         } while(0)
71 #  define LRECORD_DESCRIPTION memory_description
72 #endif  /* SXEMACS */
73
74 /*
75  * Built-in types:
76  *   byte, ubyte, char, uchar,
77  *   short, ushort, int, uint,
78  *   long, ulong,
79  *   float, double,
80  *   void, pointer, c-string
81  *
82  * Function type:
83  *
84  *   (function RET-TYPE IN-TYPE .. IN-TYPE)
85  *
86  * Array types:
87  *
88  *   (array TYPE SIZE)
89  *
90  * Structures and unions types:
91  * 
92  *   (struct|union NAME
93  *     (SLOT-NAME TYPE)
94  *     (SLOT-NAME TYPE)
95  *     ...
96  *     (SLOT-NAME TYPE))
97  *
98  * Pointers:
99  *
100  *   pointer or (pointer TYPE)
101  */
102
103 /* Foreign types */
104 Lisp_Object Q_byte, Q_unsigned_byte;
105 Lisp_Object Q_char, Q_unsigned_char;
106 Lisp_Object Q_short, Q_unsigned_short;
107 Lisp_Object Q_int, Q_unsigned_int;
108 Lisp_Object Q_long, Q_unsigned_long;
109 Lisp_Object Q_float, Q_double;
110 Lisp_Object Q_void;
111 Lisp_Object Q_array, Q_pointer;
112 Lisp_Object Q_union, Q_struct;
113 Lisp_Object Q_function;
114 Lisp_Object Q_c_string, Q_c_data;
115
116 #define FFI_POINTERP(type) (EQ(type, Q_pointer)                                \
117                             || (CONSP(type) && EQ(XCAR(type), Q_pointer)))
118
119 #define FFI_TPTR(type) (EQ(type, Q_c_string)                                   \
120                         || EQ(type, Q_c_data)                                  \
121                         || FFI_POINTERP(type)                                  \
122                         || (CONSP(type) && ((EQ(XCAR(type), Q_c_data))         \
123                                             || EQ(XCAR(type), Q_array))))
124
125 Lisp_Object Qffiobjectp;
126 Lisp_Object Qffi_translate_to_foreign;
127 Lisp_Object Qffi_translate_from_foreign;
128
129 /* Alist with elements in form (NAME . TYPE) */
130 Lisp_Object Vffi_loaded_libraries;
131 Lisp_Object Vffi_named_types;
132
133 Lisp_Object Vffi_type_checker;
134
135 static Lisp_Object Vffi_all_objects;
136
137 Lisp_Object Q_ffi_callback;
138
139 static Lisp_Object
140 mark_ffiobject(Lisp_Object obj)
141 {
142         Lisp_EffiObject *ffio = XEFFIO(obj);
143         mark_object(ffio->type);
144         mark_object(ffio->size);
145         mark_object(ffio->plist);
146         return (ffio->plist);
147 }
148
149 static void
150 print_ffiobject(Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
151 {
152         /* This function can GC */
153         Lisp_EffiObject *ffio = XEFFIO(obj);
154         escapeflag = escapeflag;        /* shutup compiler */
155         if (print_readably) {
156 #ifdef SXEMACS
157                 error("printing unreadable object #<ffiobject 0x%x>",
158                       ffio->header.uid);
159 #else
160                 signal_ferror(Qinternal_error,
161                               "printing unreadable object #<ffiobject 0x%x>",
162                               ffio->header.uid);
163 #endif  /* SXEMACS */
164         }
165         WRITE_C_STRING("#<ffiobject ", printcharfun);
166         /* Print FFIO type */
167         if (!NILP(ffio->type)) {
168                 WRITE_C_STRING("type=", printcharfun);
169                 print_internal(ffio->type, printcharfun, 1);
170                 WRITE_C_STRING(" ", printcharfun);
171         }
172         WRITE_FMT_STRING(printcharfun,"size=%ld fotype=%d foptr=%p>",
173                          (long)XINT(ffio->size), ffio->fotype, ffio->fop.generic);
174 }
175
176 static const struct LRECORD_DESCRIPTION ffiobject_description[] = {
177         {XD_LISP_OBJECT, offsetof(Lisp_EffiObject, type)},
178         {XD_LISP_OBJECT, offsetof(Lisp_EffiObject, size)},
179         {XD_LISP_OBJECT, offsetof(Lisp_EffiObject, plist)},
180         {XD_INT, offsetof(Lisp_EffiObject, fotype)},
181         {XD_OPAQUE_PTR, offsetof(Lisp_EffiObject, fop)},
182 #ifdef SXEMACS
183         {XD_SIZE_T, offsetof(Lisp_EffiObject, storage_size)},
184 #else
185         {XD_ELEMCOUNT, offsetof(Lisp_EffiObject, storage_size)},
186 #endif  /* SXEMACS */
187         {XD_END}
188 };
189
190 static Lisp_Object
191 ffi_getprop(Lisp_Object fo, Lisp_Object property)
192 {
193         return external_plist_get(&XEFFIO(fo)->plist, property, 0, ERROR_ME);
194 }
195
196 static int
197 ffi_putprop(Lisp_Object fo, Lisp_Object property, Lisp_Object value)
198 {
199         external_plist_put(&XEFFIO(fo)->plist, property, value, 0, ERROR_ME);
200         return 1;
201 }
202
203 static int
204 ffi_remprop(Lisp_Object fo, Lisp_Object property)
205 {
206         return external_remprop(&XEFFIO(fo)->plist, property, 0, ERROR_ME);
207 }
208
209 #ifdef SXEMACS
210 static size_t
211 sizeof_ffiobject(const void *header)
212 {
213         const Lisp_EffiObject *effio = (const Lisp_EffiObject *)header;
214         return (sizeof(Lisp_EffiObject) + effio->storage_size);
215 }
216 #else
217 static Bytecount
218 sizeof_ffiobject(const void *header)
219 {
220         const Lisp_EffiObject *effio = (const Lisp_EffiObject *)header;
221         return (sizeof(Lisp_EffiObject) + effio->storage_size);
222 }
223 #endif  /* SXEMACS */
224
225 /* Define ffiobject implementation */
226 const struct lrecord_implementation lrecord_ffiobject = {
227         .name = "ffiobject",
228         .marker = mark_ffiobject,
229         .printer = print_ffiobject,
230         .finalizer = 0,
231         .equal = 0,
232         .hash = 0,
233         .description = ffiobject_description,
234         .getprop = ffi_getprop,
235         .putprop = ffi_putprop,
236         .remprop = ffi_remprop,
237         .plist = Fffi_plist,
238         .static_size = 0,
239         .size_in_bytes_method = sizeof_ffiobject,
240         .lrecord_type_index = lrecord_type_ffiobject,
241         .basic_p = 0
242 };
243
244 \f
245 /** alignment in union and structures **/
246 /*
247  * x86:
248  *
249  *   - An entire structure or union is aligned on the same boundary as
250  *     its most strictly aligned member.
251  *
252  *   - Each member is assigned to the lowest available offset with the
253  *     appropriate alignment.  This may require /internal padding/,
254  *     depending on the previous member.
255  *
256  *   - A structure's size is increased, if necessary, to make it a
257  *     multiple of the alignment.  This may require /tail padding/,
258  *     depending on the last member.
259  *
260  *  Internal padding:
261  *
262  *    struct {
263  *     char c;            .-------2+---1+---0.
264  *     short s;           |  s     |pad |  c |
265  *    }                   `--------+----+----'
266  *
267  *  Internal and Tail padding:
268  *
269  *    struct {            .------------1+---0.
270  *     char c;            |     pad     |  c |
271  *     double d;          |-------------+---4|
272  *     short s;           |         d        |
273  *    }                   |-----------------8|
274  *                        |         d        |
275  *                        |------14+-------12|
276  *                        |   pad  |    s    |
277  *                        `--------+---------'
278  *
279  *  Union allocation:
280  *
281  *    union {             .------------1+---0.
282  *     char c;            |     pad     |  c |
283  *     short s;           |-------2+----+---0|
284  *     int j;             |  pad   |    s    |
285  *    }                   |--------+--------0|
286  *                        |        j         |
287  *                        `------------------'
288  */
289 static Lisp_Object
290 ffi_check_type(Lisp_Object type)
291 {
292         return apply1(Vffi_type_checker, Fcons(type, Fcons(Qt, Qnil)));
293 }
294
295 DEFUN("ffi-basic-type-p", Fffi_basic_type_p, 1, 1, 0, /*
296 Return non-nil if TYPE is a basic FFI type.
297
298 A type is said to be basic, if it is neither a pointer nor a
299 function, and there is a corresponding built-in type in C.
300 */
301       (type))
302 {
303         if (EQ(type, Q_byte) || EQ(type, Q_unsigned_byte) || EQ(type, Q_char)
304             || EQ(type, Q_unsigned_char) || EQ(type, Q_short)
305             || EQ(type, Q_unsigned_short) || EQ(type, Q_int)
306             || EQ(type, Q_unsigned_int) || EQ(type, Q_long)
307             || EQ(type, Q_unsigned_long) || EQ(type, Q_float)
308             || EQ(type, Q_double) || EQ(type, Q_void)
309             || EQ(type, Q_c_string) || EQ(type, Q_c_data)
310             || (CONSP(type) && EQ(XCAR(type), Q_c_data)))
311                 return Qt;
312         else
313                 return Qnil;
314 }
315
316
317 static Lisp_Object
318 ffi_canonicalise_type(Lisp_Object type)
319 {
320 /* this function canNOT GC */
321
322         while (!NILP(type) && NILP(Fffi_basic_type_p(type)) && SYMBOLP(type)) {
323                 if EQ(type, Q_pointer)
324                         break;
325                 type = Fcdr(Fassq(type, Vffi_named_types));
326         }
327
328         return type;
329 }
330
331 DEFUN("ffi-canonicalise-type", Fffi_canonicalise_type, 1, 1, 0, /*
332 Return FFI type TYPE in a canonical form.
333 */
334       (type))
335 {
336         Lisp_Object canon_type = ffi_canonicalise_type(type);
337         if (NILP(canon_type)) {
338 #ifdef SXEMACS
339                 signal_simple_error("No such FFI type", type);
340 #else
341                 signal_error(Qinternal_error, "No such FFI type", type);
342 #endif  /* SXEMACS */
343         }
344         return canon_type;
345 }
346
347 DEFUN("ffi-size-of-type", Fffi_size_of_type, 1, 1, 0,   /*
348 Return the size of the foreign type TYPE.
349
350 Valid foreign types are: `byte', `unsigned-byte', `char',
351 `unsigned-char', `short', `unsigned-short', `int', `unsigned-int',
352 `long', `unsigned-long', `pointer', `float', `double', 
353 `object', and `c-string'.
354 */
355       (type))
356 {
357         int tsize;
358
359         type = ffi_canonicalise_type(type);
360         if (EQ(type, Q_void))
361                 tsize = 0;
362         else if (EQ(type, Q_byte))
363                 tsize = sizeof(int8_t);
364         else if (EQ(type, Q_unsigned_byte))
365                 tsize = sizeof(uint8_t);
366         else if (EQ(type, Q_char))
367                 tsize = sizeof(char);
368         else if (EQ(type, Q_unsigned_char))
369                 tsize = sizeof(unsigned char);
370         else if (EQ(type, Q_short))
371                 tsize = sizeof(short);
372         else if (EQ(type, Q_unsigned_short))
373                 tsize = sizeof(unsigned short);
374         else if (EQ(type, Q_int))
375                 tsize = sizeof(int);
376         else if (EQ(type, Q_unsigned_int))
377                 tsize = sizeof(unsigned int);
378         else if (EQ(type, Q_long))
379                 tsize = sizeof(long);
380         else if (EQ(type, Q_unsigned_long))
381                 tsize = sizeof(unsigned long);
382         else if (EQ(type, Q_float))
383                 tsize = sizeof(float);
384         else if (EQ(type, Q_double))
385                 tsize = sizeof(double);
386         else if (EQ(type, Q_c_string))
387                 tsize = sizeof(char *);
388         else if (FFI_POINTERP(type))
389                 tsize = sizeof(void *);
390         else if (EQ(type, Q_c_data))
391                 tsize = sizeof(void *);
392         else if (CONSP(type) && EQ(XCAR(type), Q_c_data)) {
393                 Lisp_Object cdsize = XCDR(type);
394                 CHECK_INT(cdsize);
395                 tsize = XINT(cdsize);
396         } else if (CONSP(type) && EQ(XCAR(type), Q_function))
397                 tsize = sizeof(void(*));
398         else if (CONSP(type) && EQ(XCAR(type), Q_array)) {
399                 Lisp_Object atype = Fcar(XCDR(type));
400                 Lisp_Object asize = Fcar(Fcdr(XCDR(type)));
401
402                 CHECK_INT(asize);
403                 tsize = XINT(asize) * XINT(Fffi_size_of_type(atype));
404         } else if (CONSP(type) && EQ(XCAR(type), Q_struct)) {
405                 return Fffi_slot_offset(type, Qnil);
406         } else if (CONSP(type) && EQ(XCAR(type), Q_union)) {
407                 Lisp_Object slots = Fcdr(XCDR(type));
408
409                 CHECK_CONS(slots);
410
411                 tsize = 0;
412                 while (!NILP(slots)) {
413                         Lisp_Object slot_type = Fcar(Fcdr(XCAR(slots)));
414                         int slot_size = XINT(Fffi_size_of_type(slot_type));
415                         if (slot_size > tsize)
416                                 tsize = slot_size;
417                         slots = XCDR(slots);
418                 }
419         } else {
420 #ifdef SXEMACS
421                 signal_simple_error("Unrecognized foreign type", type);
422 #else
423                 signal_error(Qinternal_error, "Unrecognized foreign type", type);
424 #endif  /* SXEMACS */
425         }
426
427         return make_int(tsize);
428 }
429
430 DEFUN("make-ffi-object", Fmake_ffi_object, 1, 2, 0, /*
431 Create a new FFI object of type TYPE.
432 If optional argument SIZE is non-nil it should be an
433 integer, in this case additional storage size to hold data 
434 of at least length SIZE is allocated.
435 */
436       (type, size))
437 {
438         int cs_or_cd;
439         Lisp_Object ctype;
440         Lisp_Object result = Qnil;
441         Lisp_EffiObject *ffio;
442         struct gcpro gcpro1;
443
444         GCPRO1(result);
445
446         /* NOTE: ffi_check_type returns canonical type */
447         ctype = ffi_check_type(type);
448         if (NILP(size))
449                 size = Fffi_size_of_type(type);
450         CHECK_INT(size);
451
452         if (CONSP(ctype) && EQ(XCAR(ctype), Q_c_data) && INTP(XCDR(ctype)))
453                 size = XCDR(type);
454
455         cs_or_cd = EQ(ctype, Q_c_string) || (EQ(ctype, Q_c_data));
456         if ((cs_or_cd && (XINT(size) < 1))
457             || (!(cs_or_cd || FFI_POINTERP(ctype))
458                 && (XINT(size) < XINT(Fffi_size_of_type(type)))))
459 #ifdef SXEMACS
460                 signal_simple_error("storage size too small to store type",
461                                     list2(size, type));
462
463         ffio = alloc_lcrecord(sizeof(Lisp_EffiObject)+XINT(size),
464                               &lrecord_ffiobject);
465         XSETEFFIO(result, ffio);
466 #else
467                 signal_error(Qinternal_error,
468                              "storage size too small to store type",
469                              list2(size, type));
470
471         ffio = old_basic_alloc_lcrecord(sizeof(Lisp_EffiObject)+XINT(size),
472                                         &lrecord_ffiobject);
473         result = wrap_effio(ffio);
474 #endif  /* SXEMACS */
475
476         ffio->size = Fffi_size_of_type(type);
477         ffio->type = type;
478         ffio->plist = Qnil;
479
480         /* Initialize foreign pointer */
481         ffio->fotype = EFFI_FOT_NONE;
482         ffio->storage_size = XINT(size);
483         ffio->fop.ptr = ffio->fostorage;
484
485         if (!NILP(Vffi_all_objects))
486                 XWEAK_LIST_LIST(Vffi_all_objects) =
487                         Fcons(result, XWEAK_LIST_LIST(Vffi_all_objects));
488
489         RETURN_UNGCPRO(result);
490 }
491
492 DEFUN("ffi-object-p", Fffi_object_p, 1, 1, 0, /*
493 Return non-nil if FO is an FFI object, nil otherwise.
494 */
495       (fo))
496 {
497         return (EFFIOP(fo) ? Qt : Qnil);
498 }
499
500 DEFUN("ffi-object-address", Fffi_object_address, 1, 1, 0, /*
501 Return the address FO points to.
502 */
503       (fo))
504 {
505         CHECK_EFFIO(fo);
506         return make_float((long)XEFFIO(fo)->fop.ptr);
507 }
508
509 DEFUN("ffi-make-pointer", Fffi_make_pointer, 1, 1, 0, /*
510   "Return a pointer pointing to ADDRESS."
511 */
512       (address))
513 {
514         long addr;
515         Lisp_Object ptr;
516
517         if (INTP(address))
518                 addr = XINT(address);
519         else if (FLOATP(address))
520                 addr = XFLOATINT(address);
521         else {
522 #ifdef SXEMACS
523                 signal_simple_error("FFI: invalid address type", address);
524 #else
525                 signal_error(Qinternal_error, "FFI: invalid address type",
526                              address);
527 #endif  /* SXEMACS */
528         }
529
530         ptr = Fmake_ffi_object(Q_pointer, Qnil);
531         XEFFIO(ptr)->fop.ptr = (void*)addr;
532         return ptr;
533 }
534
535 DEFUN("ffi-object-canonical-type", Fffi_object_canonical_type, 1, 1, 0, /*
536 Return FO's real type, that is after resolving user defined types.
537 */
538       (fo))
539 {
540         CHECK_EFFIO(fo);
541         return ffi_canonicalise_type(XEFFIO(fo)->type);
542 }
543
544 DEFUN("ffi-object-type", Fffi_object_type, 1, 1, 0, /*
545 Return FO's type.
546 */
547       (fo))
548 {
549         CHECK_EFFIO(fo);
550         return (XEFFIO(fo)->type);
551 }
552
553 DEFUN("ffi-set-object-type", Fffi_set_object_type, 2, 2, 0, /*
554 Cast FO to type TYPE and reassign the cast value.
555 */
556       (fo, type))
557 {
558         CHECK_EFFIO(fo);
559
560         ffi_check_type(type);
561         XEFFIO(fo)->type = type;
562
563         return type;
564 }
565
566 DEFUN("ffi-object-size", Fffi_object_size, 1, 1, 0, /*
567 Return the size of the allocated space of FO.
568 */
569       (fo))
570 {
571         CHECK_EFFIO(fo);
572         return (XEFFIO(fo)->size);
573 }
574
575 DEFUN("ffi-set-storage-size", Fffi_set_storage_size, 2, 2, 0, /*
576 Set the size of the allocated space of FO.
577 */
578       (fo, size))
579 {
580         CHECK_EFFIO(fo);
581         CHECK_INT(size);
582         XEFFIO(fo)->storage_size = XUINT(size);
583         return Qt;
584 }
585
586 DEFUN("ffi-load-library", Fffi_load_library, 1, 1, 0, /*
587 Load library LIBNAME and return a foreign object handle if successful,
588 or `nil' if the library cannot be loaded.
589
590 The argument LIBNAME should be the file-name string of a shared object
591 library.  Normally you should omit the file extension, as this
592 function will add the appripriate extension for the current platform
593 if one is missing.
594
595 The library should reside in one of the directories specified by the
596 $LD_LIBRARY_PATH environment variable or the more global ld.so.cache.
597 */
598       (libname))
599 {
600
601 #ifdef LTDL_SHLIB_EXT
602 #  define EXT LTDL_SHLIB_EXT
603 #elif defined(HAVE_DYLD) || defined(HAVE_MACH_O_DYLD_H)
604 #    define EXT ".dylib"
605 #  else
606 #    define EXT ".so"
607 #endif  /* LTDL_SHLIB_EXT */
608
609         void *handler, *dotpos;
610         Lisp_Object fo = Qnil;
611         Lisp_EffiObject *ffio;
612         struct gcpro gcpro1;
613         char *soname = NULL;
614
615         CHECK_STRING(libname);
616
617         /* Add an extension if we need to */
618         dotpos = strrchr((char *)XSTRING_DATA(libname),'.');
619         if ( dotpos == NULL || strncmp(dotpos, EXT, sizeof(EXT))) {
620                 ssize_t liblen = XSTRING_LENGTH(libname);
621                 ssize_t soname_len = liblen + sizeof(EXT);
622                 soname = xmalloc( soname_len + 1);
623                 strncpy(soname, (char *)XSTRING_DATA(libname), liblen+1);
624                 strncat(soname, EXT, sizeof(EXT)+1);
625         }
626
627         if ( soname == NULL ) {
628                 handler = dlopen((const char *)XSTRING_DATA(libname),
629                                  RTLD_GLOBAL|RTLD_NOW);
630         } else {
631                 handler = dlopen(soname, RTLD_GLOBAL|RTLD_NOW);
632                 xfree(soname);
633         }
634
635         if (handler == NULL)
636                 return Qnil;
637         
638         GCPRO1(fo);
639         fo = Fmake_ffi_object(Q_pointer, Qnil);
640         ffio = XEFFIO(fo);
641
642         ffio->fotype = EFFI_FOT_BIND;
643         ffio->fop.ptr = handler;
644         
645         RETURN_UNGCPRO(fo);
646 }
647
648 DEFUN("ffi-bind", Fffi_bind, 2, 2, 0, /*
649 Make and return a foreign object of type TYPE and bind it to the
650 external symbol SYM.
651
652 The argument TYPE can be any type-cell.
653 The argument SYM should be a string naming an arbitrary symbol
654 in one of the loaded libraries.
655
656 If SYM does not exist in any of the loaded libraries, `nil' is
657 returned.
658 */
659       (type, sym))
660 {
661         Lisp_Object fo = Qnil;
662         Lisp_EffiObject *ffio;
663         struct gcpro gcpro1;
664
665         ffi_check_type(type);
666         CHECK_STRING(sym);
667
668         GCPRO1(fo);
669         fo = Fmake_ffi_object(type, Qnil);
670         ffio = XEFFIO(fo);
671         ffio->fop.ptr = dlsym(RTLD_DEFAULT, (const char*)XSTRING_DATA(sym));
672         if (ffio->fop.ptr == NULL) {
673                 UNGCPRO;
674                 return Qnil;
675         }
676
677         ffio->fotype = EFFI_FOT_BIND;
678
679         RETURN_UNGCPRO(fo);
680 }
681
682 DEFUN("ffi-dlerror", Fffi_dlerror, 0, 0, 0, /*
683 Return dl error string.
684 */
685       ())
686 {
687         const char *dles = dlerror();
688
689         if (LIKELY(dles != NULL)) {
690                 size_t sz = strlen(dles);
691                 return make_ext_string((const Extbyte*)dles, sz, EFFI_CODING);
692         } else {
693                 return Qnil;
694         }
695 }
696
697 DEFUN("ffi-defun", Fffi_defun, 2, 2, 0, /*
698 Make and return a foreign object of type TYPE and bind it to the
699 external symbol SYM.
700
701 The argument TYPE should be a function type-cell.
702 The argument SYM should be a string naming a function in one of
703 the loaded libraries.
704
705 If SYM does not exist in any of the loaded libraries, an error
706 is indicated.
707
708 This is like `ffi-bind' but for function objects.
709 */
710       (type, sym))
711 {
712         Lisp_Object fo = Qnil;
713         Lisp_EffiObject *ffio;
714         struct gcpro gcpro1;
715
716         ffi_check_type(type);
717         CHECK_STRING(sym);
718         
719         GCPRO1(fo);
720
721         fo = Fmake_ffi_object(type, Qnil);
722         ffio = XEFFIO(fo);
723         ffio->fop.fun = dlsym(RTLD_DEFAULT, (const char *)XSTRING_DATA(sym));
724         if (ffio->fop.fun == NULL) {
725 #ifdef SXEMACS
726                 signal_simple_error("Can't define function", sym);
727 #else
728                 signal_error(Qinternal_error, "Can't define function", sym);
729 #endif  /* SXEMACS */
730         }
731
732         ffio->fotype = EFFI_FOT_FUNC;
733
734         RETURN_UNGCPRO(fo);
735 }
736
737 /*
738  * Return alignment policy for struct or union FFI_SU.
739  * x86: Return 1, 2 or 4.
740  * mips: Return 1, 2, 4 or 8.
741  */
742 static int
743 ffi_type_align(Lisp_Object type)
744 {
745         type = ffi_canonicalise_type(type);
746         if (SYMBOLP(type)) {
747                 if (EQ(type, Q_byte) || EQ(type, Q_unsigned_byte)
748                     || EQ(type, Q_char) || EQ(type, Q_unsigned_char))
749                         return 1;
750                 if (EQ(type, Q_short) || EQ(type, Q_unsigned_short))
751                         return 2;
752 #ifdef FFI_MIPS
753                 if (EQ(type, Q_double))
754                         return 8;
755 #endif  /* FFI_MIPS */
756                 return 4;
757                 /* NOT REACHED */
758         } else if (CONSP(type)
759                    && (EQ(XCAR(type), Q_struct) || EQ(XCAR(type), Q_union))) {
760                 int al;
761
762                 for (al = 0, type = Fcdr(Fcdr(type));
763                      !NILP(type);
764                      type = Fcdr(type))
765                 {
766                         Lisp_Object stype = Fcar(Fcdr(Fcar(type)));
767                         int tmp_al = ffi_type_align(stype);
768
769                         if (tmp_al > al)
770                                 al = tmp_al;
771                 }
772
773                 return al;
774         }
775
776         return 4;
777 }
778
779 DEFUN("ffi-type-alignment", Fffi_type_alignment, 1, 1, 0, /*
780 Return TYPE alignment.
781 */
782       (type))
783 {
784         return make_int(ffi_type_align(type));
785 }
786
787 DEFUN("ffi-slot-offset", Fffi_slot_offset, 2, 2, 0, /*
788 Return the offset of SLOT in TYPE.
789 SLOT can be either a valid (named) slot in TYPE or `nil'.
790 If SLOT is `nil' return the size of the struct.
791 */
792       (type, slot))
793 {
794         Lisp_Object slots;
795         int lpad, align, retoff;
796
797         type = ffi_canonicalise_type(type);
798         if (!CONSP(type)) {
799 #ifdef SXEMACS
800                 error("Not struct or union");
801 #else
802                 Fsignal(Qwrong_type_argument,
803                         list2(Qstringp, build_string("Not struct or union")));
804 #endif  /* SXEMACS */
805         }
806
807         retoff = 0;
808         lpad = align = ffi_type_align(type);
809         slots = Fcdr(XCDR(type));
810         CHECK_CONS(slots);
811         while (!NILP(slots)) {
812                 Lisp_Object tmp_slot = Fcar(Fcdr(XCAR(slots)));
813                 int tmp_align;
814                 int tmp_size;
815
816                 /*
817                  * NOTE:
818                  *  - for basic types TMP_ALIGN and TMP_SIZE are equal
819                  */
820                 tmp_align = ffi_type_align(tmp_slot);
821
822                 if (EQ(XCAR(XCAR(slots)), slot)) {
823                         /* SLOT found */
824                         /* TODO: add support for :offset keyword in SLOT */
825                         if (lpad < tmp_align) {
826                                 retoff += lpad;
827                                 lpad = 0;
828                         } else
829                                 lpad -= tmp_align;
830                         break;
831                 }
832
833                 tmp_size = XINT(Fffi_size_of_type(tmp_slot));
834                 while (tmp_size > 0) {
835                         if (lpad < tmp_align) {
836                                 retoff += lpad;
837                                 lpad = align;
838                         }
839                         tmp_size -= tmp_align;
840                         lpad -= tmp_align;
841                         retoff += tmp_align;
842                 }
843
844                 slots = XCDR(slots);
845         }
846         if (NILP(slots) && !NILP(slot)) {
847 #ifdef SXEMACS
848                 signal_simple_error("FFI: Slot not found", slot);
849 #else
850                 signal_error(Qinternal_error, "FFI: Slot not found", slot);
851 #endif  /* SXEMACS */
852         }
853         return make_int(retoff + lpad);
854 }
855
856 /*
857  * TYPE must be already canonicalised
858  */
859 static Lisp_Object
860 ffi_fetch_foreign(void *ptr, Lisp_Object type)
861 {
862 /* this function canNOT GC */
863         Lisp_Object retval = Qnone;
864
865         if (EQ(type, Q_char))
866                 retval = make_char(*(char*)ptr);
867         else if (EQ(type, Q_unsigned_char))
868                 retval = make_char(*(char unsigned*)ptr);
869         else if (EQ(type, Q_byte))
870                 retval = make_int(*(char*)ptr);
871         else if (EQ(type, Q_unsigned_byte))
872                 retval = make_int(*(unsigned char*)ptr);
873         else if (EQ(type, Q_short))
874                 retval = make_int(*(short*)ptr);
875         else if (EQ(type, Q_unsigned_short))
876                 retval = make_int(*(unsigned short*)ptr);
877         else if (EQ(type, Q_int))
878                 retval = make_int(*(int*)ptr);
879         else if (EQ(type, Q_unsigned_int))
880                 retval = make_int(*(unsigned int*)ptr);
881         else if (EQ(type, Q_long))
882                 retval = make_int(*(long*)ptr);
883         else if (EQ(type, Q_unsigned_long))
884                 retval = make_int(*(unsigned long*)ptr);
885         else if (EQ(type, Q_float))
886                 retval = make_float(*(float*)ptr);
887         else if (EQ(type, Q_double))
888                 retval = make_float(*(double*)ptr);
889         else if (EQ(type, Q_c_string)) {
890                 retval = build_ext_string((char*)ptr, Qbinary);
891         } else if (EQ(type, Q_void)) {
892                 retval = Qnil;
893         } else if (FFI_POINTERP(type)) {
894                 retval = Fmake_ffi_object(type, Qnil);
895                 XEFFIO(retval)->fop.ptr = *(void**)ptr;
896         } else if (CONSP(type) && EQ(XCAR(type), Q_function)) {
897                 retval = Fmake_ffi_object(type, Qnil);
898                 XEFFIO(retval)->fop.fun = (void*)ptr;
899                 XEFFIO(retval)->fotype = EFFI_FOT_FUNC;
900         }
901
902         return retval;
903 }
904
905 DEFUN("ffi-fetch", Fffi_fetch, 3, 3, 0, /*
906 Fetch value from the foreign object FO from OFFSET position.
907 TYPE specifies value for data to be fetched.
908 */
909       (fo, offset, type))
910 {
911         Lisp_Object origtype = type;
912         Lisp_Object retval = Qnil;
913         Lisp_EffiObject *ffio;
914         void *ptr;
915         struct gcpro gcpro1;
916
917         CHECK_EFFIO(fo);
918         CHECK_INT(offset);
919
920         ffio = XEFFIO(fo);
921         ptr = (void*)((char*)ffio->fop.ptr + XINT(offset));
922
923         type = ffi_canonicalise_type(type);
924
925         GCPRO1(retval);
926         /* Fetch value and translate it according to translators */
927         retval = ffi_fetch_foreign(ptr, type);
928         if (EQ(retval, Qnone)) {
929                 /* Special case for c-data */
930                 if (EQ(type, Q_c_data) ||
931                     (CONSP(type) && EQ(XCAR(type), Q_c_data)))
932                 {
933                         size_t tlen;
934                         if (EQ(type, Q_c_data)) {
935                                 tlen = ffio->storage_size - XINT(offset);
936                         } else {
937                                 CHECK_INT(XCDR(type));
938                                 tlen = XUINT(XCDR(type));
939                         }
940
941                         retval = make_ext_string(ptr, tlen, Qbinary);
942                 } else {
943 #ifdef SXEMACS
944                         signal_simple_error("Can't fetch for this type", origtype);
945 #else
946                         signal_error(Qinternal_error, "Can't fetch for this type",
947                                      origtype);
948 #endif  /* SXEMACS */
949                 }
950         }
951         retval = apply1(Findirect_function(Qffi_translate_from_foreign),
952                         list2(retval, origtype));
953
954         RETURN_UNGCPRO(retval);
955 }
956
957 DEFUN("ffi-aref", Fffi_aref, 2, 2, 0, /*
958 Return the element of FARRAY at index IDX (starting with 0).
959 */
960       (farray, idx))
961 {
962         Lisp_Object type;
963         
964         CHECK_EFFIO(farray);
965         CHECK_INT(idx);
966         
967         type = ffi_canonicalise_type(XEFFIO(farray)->type);
968         if (!FFI_TPTR(type)) {
969 #ifdef SXEMACS
970                 signal_simple_error("Not an array type", type);
971 #else
972                 signal_error(Qinternal_error, "Not an array type", type);
973 #endif  /* SXEMACS */
974         }
975         if (EQ(type, Q_c_string))
976                 type = Q_char;
977         else
978                 type = Fcar(XCDR(type));
979
980         return Fffi_fetch(farray,
981                           make_int(XINT(Fffi_size_of_type(type)) * XINT(idx)),
982                           type);
983 }
984
985 DEFUN("ffi-store", Fffi_store, 4, 4, 0, /*
986 For foreign object FO at specified OFFSET store data.
987 Type of data is specified by VAL-TYPE and data itself specified in VAL.
988
989 VAL-TYPE can be either a basic FFI type or an FFI pointer.
990 If VAL-TYPE is a basic FFI type, then VAL can be an
991 ordinary, but suitable Emacs lisp object.
992 If VAL-TYPE is an FFI pointer then VAL _must_ be an FFI
993 object of the underlying type pointed to.
994 */
995       (fo, offset, val_type, val))
996 {
997         Lisp_Object origtype = val_type;
998         Lisp_EffiObject *ffio;
999         void *ptr;
1000
1001         CHECK_EFFIO(fo);
1002         CHECK_INT(offset);
1003
1004         ffio = XEFFIO(fo);
1005         ptr = (void*)((char*)ffio->fop.ptr + XINT(offset));
1006
1007         val_type = ffi_canonicalise_type(val_type);
1008
1009         /* Translate value */
1010         val = apply1(Findirect_function(Qffi_translate_to_foreign),
1011                      list2(val, origtype));
1012
1013         if (EQ(val_type, Q_char) || EQ(val_type, Q_unsigned_char)) {
1014                 if (!CHARP(val)) {
1015                         SIGNAL_ERROR(Qwrong_type_argument,
1016                                      list2(Qcharacterp, val));
1017                 }
1018                 *(char*)ptr = XCHAR(val);
1019         } else if (EQ(val_type, Q_byte) || EQ(val_type, Q_unsigned_byte)) {
1020                 if (!INTP(val)) {
1021                         SIGNAL_ERROR(Qwrong_type_argument,
1022                                      list2(Qintegerp, val));
1023                 }
1024                 *(char*)ptr = XINT(val);
1025         } else if (EQ(val_type, Q_short) || EQ(val_type, Q_unsigned_short)) {
1026                 if (!INTP(val)) {
1027                         SIGNAL_ERROR(Qwrong_type_argument,
1028                                      list2(Qintegerp, val));
1029                 }
1030                 *(short*)ptr = (short)XINT(val);
1031         } else if (EQ(val_type, Q_int) || EQ(val_type, Q_unsigned_int)) {
1032                 if (INTP(val)) {
1033                         *(int*)ptr = XINT(val);
1034                 } else if (FLOATP(val)) {
1035                         fpfloat tmp = XFLOATINT(val);
1036                         *(int*)ptr = (int)tmp;
1037                 } else {
1038                         SIGNAL_ERROR(Qwrong_type_argument,
1039                                      list2(Qfloatp, val));
1040                 }
1041         } else if (EQ(val_type, Q_long) || EQ(val_type, Q_unsigned_long)) {
1042                 if (INTP(val)) {
1043                         *(long*)ptr = (long)XINT(val);
1044                 } else if (FLOATP(val)) {
1045                         fpfloat tmp = XFLOATINT(val);
1046                         *(long*)ptr = (long int)tmp;
1047                 } else {
1048                         SIGNAL_ERROR(Qwrong_type_argument, list2(Qfloatp, val));
1049                 }
1050         } else if (EQ(val_type, Q_float)) {
1051                 if (!FLOATP(val))
1052                         SIGNAL_ERROR(Qwrong_type_argument, list2(Qfloatp, val));
1053                 *(float*)ptr = XFLOATINT(val);
1054         } else if (EQ(val_type, Q_double)) {
1055                 if (!FLOATP(val))
1056                         SIGNAL_ERROR(Qwrong_type_argument, list2(Qfloatp, val));
1057                 *(double*)ptr = XFLOAT_DATA(val);
1058         } else if (EQ(val_type, Q_c_string)) {
1059                 char *tmp;
1060                 int tmplen;
1061                 if (!STRINGP(val))
1062                         SIGNAL_ERROR(Qwrong_type_argument, list2(Qstringp, val));
1063 #if defined(MULE)
1064                 TO_EXTERNAL_FORMAT(LISP_STRING, val,
1065                                    ALLOCA, (tmp, tmplen), Qnil);
1066                 memcpy((char*)ptr, tmp, tmplen + 1);
1067 #else
1068                 memcpy((char*)ptr,
1069                        (const char *)XSTRING_DATA(val),
1070                        XSTRING_LENGTH(val) + 1);
1071 #endif
1072         } else if (EQ(val_type, Q_c_data) ||
1073                    (CONSP(val_type) &&
1074                     EQ(XCAR(val_type), Q_c_data) && INTP(XCDR(val_type)))) {
1075                 char *val_ext = NULL;
1076                 unsigned int val_ext_len;
1077                 if (!STRINGP(val))
1078                         SIGNAL_ERROR(Qwrong_type_argument, list2(Qstringp, val));
1079
1080                 TO_EXTERNAL_FORMAT(LISP_STRING, val, ALLOCA,
1081                                    (val_ext, val_ext_len), Qbinary);
1082                 if (val_ext == NULL || 
1083                     (CONSP(val_type) && (val_ext_len > XINT(XCDR(val_type))))) {
1084 #ifdef SXEMACS
1085                         error("storage size too small");
1086 #else
1087                         Fsignal(Qrange_error,
1088                                 list2(Qstringp,
1089                                       build_string("storage size too small")));
1090 #endif  /* SXEMACS */
1091                 } else {
1092                         memcpy((char*)ptr, (const char *)val_ext, val_ext_len);
1093                 }
1094         } else if (FFI_POINTERP(val_type)) {
1095                 if (!EFFIOP(val)) {
1096 #ifdef SXEMACS
1097                         signal_simple_error("FFI: Value not of pointer type", \
1098                                             list2(origtype, val));
1099 #else
1100                         Fsignal(Qwrong_type_argument,
1101                                 list2(Qstringp, build_string("type")));
1102 #endif  /* SXEMACS */
1103                 }
1104                 *(void**)ptr = (void*)XEFFIO(val)->fop.ptr;
1105         } else if (CONSP(val_type) && EQ(XCAR(val_type), Q_struct)) {
1106                 if (!EFFIOP(val)) {
1107 #ifdef SXEMACS
1108                         signal_simple_error("FFI: Value not FFI object", \
1109                                             list2(origtype, val));
1110 #else
1111                         Fsignal(Qwrong_type_argument,
1112                                 list2(Qstringp, build_string("type")));
1113 #endif  /* SXEMACS */
1114                 }
1115                 memcpy((char*)ptr, (const char *)XEFFIO(val)->fop.ptr, \
1116                        XINT(Fffi_size_of_type(val_type)));
1117         } else {
1118 #ifdef SXEMACS
1119                 signal_simple_error("FFI: Non basic or pointer type", origtype);
1120 #else
1121                 Fsignal(Qinternal_error,
1122                         list2(Qstringp,
1123                               build_string("non basic or pointer type")));
1124 #endif  /* SXEMACS */
1125         }
1126
1127         return val;
1128 }
1129
1130 DEFUN("ffi-aset", Fffi_aset, 3, 3, 0, /*
1131 Store the element VALUE in FARRAY at index IDX (starting with 0).
1132 */
1133       (farray, idx, value))
1134 {
1135         Lisp_Object type;
1136         
1137         CHECK_EFFIO(farray);
1138         CHECK_INT(idx);
1139         
1140         type = ffi_canonicalise_type(XEFFIO(farray)->type);
1141         if (!FFI_TPTR(type)) {
1142 #ifdef SXEMACS
1143                 signal_simple_error("Not an array type", type);
1144 #else
1145                 signal_error(Qinternal_error, "Not an array type", type);
1146 #endif  /* SXEMACS */
1147         }
1148         if (EQ(type, Q_c_string))
1149                 type = Q_char;
1150         else
1151                 type = Fcar(XCDR(type));
1152
1153         return Fffi_store(farray,
1154                           make_int(XINT(Fffi_size_of_type(type)) * XINT(idx)),
1155                           type, value);
1156 }
1157
1158 DEFUN("ffi-address-of", Fffi_address_of, 1, 1, 0, /*
1159 Return the FFI object that stores the address of given FFI object FO.
1160
1161 This is the equivalent of the `&' operator in C.
1162 */
1163       (fo))
1164 {
1165         Lisp_Object newfo = Qnil;
1166         Lisp_EffiObject *ffio, *newffio;
1167         struct gcpro gcpro1;
1168
1169         CHECK_EFFIO(fo);
1170         ffio = XEFFIO(fo);
1171
1172         GCPRO1(newfo);
1173         newfo = Fmake_ffi_object(Q_pointer, Qnil);
1174         newffio = XEFFIO(newfo);
1175
1176         newffio->fotype = EFFI_FOT_BIND;
1177         if (FFI_TPTR(ffio->type))
1178                 newffio->fop.ptr = (void*)&ffio->fop.ptr;
1179         else
1180                 newffio->fop.ptr = ffio->fop.ptr;
1181
1182         RETURN_UNGCPRO(newfo);
1183 }
1184
1185 DEFUN("ffi-lisp-object-to-pointer", Fffi_lisp_object_to_pointer, 1, 1, 0, /*
1186 Convert lisp object to FFI pointer.
1187 */
1188       (obj))
1189 {
1190         Lisp_Object newfo = Qnil;
1191         Lisp_EffiObject *newffio;
1192         struct gcpro gcpro1;
1193
1194         GCPRO1(obj);
1195
1196         newfo = Fmake_ffi_object(Q_pointer, Qnil);
1197         newffio = XEFFIO(newfo);
1198         newffio->fotype = EFFI_FOT_BIND;
1199         newffio->fop.ptr = (void*)obj;
1200
1201         /* Hold a reference to OBJ in NEWFO's plist */
1202         Fput(newfo, intern("lisp-object"), obj);
1203
1204         RETURN_UNGCPRO(newfo);
1205 }
1206
1207 DEFUN("ffi-pointer-to-lisp-object", Fffi_pointer_to_lisp_object, 1, 1, 0, /*
1208 Convert FFI pointer to lisp object.
1209 */
1210       (ptr))
1211 {
1212         CHECK_EFFIO(ptr);
1213         return (Lisp_Object)XEFFIO(ptr)->fop.ptr;
1214 }
1215
1216 DEFUN("ffi-plist", Fffi_plist, 1, 1, 0, /*
1217 Return properties list for FFI object FO.
1218 */
1219       (fo))
1220 {
1221         CHECK_EFFIO(fo);
1222         return (XEFFIO(fo)->plist);
1223 }
1224
1225 #ifdef HAVE_LIBFFI
1226
1227 static int lf_cindex = 0;
1228
1229 /*
1230  * XXX
1231  *  This will work in most cases.
1232  *  However it might not work for large structures,
1233  *  In general we should allocate these spaces dynamically
1234  */
1235 #define MAX_TYPES_VALUES 1024
1236 /* ex_ffitypes_dummies used for structure types */
1237 static ffi_type ex_ffitypes_dummies[MAX_TYPES_VALUES + 1];
1238 static ffi_type *ex_ffitypes[MAX_TYPES_VALUES + 1];
1239 static void *ex_values[MAX_TYPES_VALUES + 1];
1240
1241 #if SIZEOF_LONG == 4
1242 #  define effi_type_ulong ffi_type_uint32
1243 #  define effi_type_slong ffi_type_sint32
1244 #elif SIZEOF_LONG == 8
1245 #  define effi_type_ulong ffi_type_uint64
1246 #  define effi_type_slong ffi_type_sint64
1247 #endif
1248
1249 static void
1250 extffi_setup_argument(Lisp_Object type, ffi_type **ft)
1251 {
1252         type = ffi_canonicalise_type(type);
1253         if (EQ(type, Q_char) || EQ(type, Q_byte))
1254                 *ft = &ffi_type_schar;
1255         else if (EQ(type, Q_unsigned_char) || EQ(type, Q_unsigned_byte))
1256                 *ft = &ffi_type_uchar;
1257         else if (EQ(type, Q_short))
1258                 *ft = &ffi_type_sshort;
1259         else if (EQ(type, Q_unsigned_short))
1260                 *ft = &ffi_type_ushort;
1261         else if (EQ(type, Q_int))
1262                 *ft = &ffi_type_sint;
1263         else if (EQ(type, Q_unsigned_int))
1264                 *ft = &ffi_type_uint;
1265         else if (EQ(type, Q_unsigned_long))
1266                 *ft = &effi_type_ulong;
1267         else if (EQ(type, Q_long))
1268                 *ft = &effi_type_slong;
1269         else if (EQ(type, Q_float))
1270                 *ft = &ffi_type_float;
1271         else if (EQ(type, Q_double))
1272                 *ft = &ffi_type_double;
1273         else if (EQ(type, Q_void))
1274                 *ft = &ffi_type_void;
1275         else if (FFI_TPTR(type))
1276                 *ft = &ffi_type_pointer;
1277         else if (CONSP(type) && EQ(XCAR(type), Q_struct)) {
1278                 Lisp_Object slots = Fcdr(XCDR(type));
1279                 ffi_type **ntypes;
1280                 int nt_size, i;
1281
1282                 CHECK_CONS(slots);
1283
1284                 nt_size = XINT(Flength(slots)) + 1;
1285                 if (nt_size + lf_cindex > MAX_TYPES_VALUES) {
1286                         lf_cindex = 0;  /* reset cindex */
1287 #ifdef SXEMACS
1288                         error("cindex overflow");
1289 #else
1290                         Fsignal(Qoverflow_error,
1291                                 list2(Qstringp,
1292                                       build_string("cindex overflow")));
1293 #endif  /* SXEMACS */
1294                 }
1295                 ntypes = &ex_ffitypes[lf_cindex];
1296                 *ft = &ex_ffitypes_dummies[lf_cindex];
1297
1298                 /* Update lf_cindex in case TYPE struct contains other
1299                  * structures */
1300                 lf_cindex += nt_size;
1301
1302                 (*ft)->type = FFI_TYPE_STRUCT;
1303                 (*ft)->alignment = ffi_type_align(type);
1304                 (*ft)->elements = ntypes;
1305
1306                 for (i = 0; (i < nt_size) && !NILP(slots); slots = XCDR(slots), i++)
1307                         extffi_setup_argument(Fcar(Fcdr(XCAR(slots))), &ntypes[i]);
1308                 ntypes[i] = NULL;
1309         } else {
1310 #ifdef SXEMACS
1311                 signal_simple_error("Can't setup argument for type", type);
1312 #else
1313                 signal_error(Qinternal_error,
1314                              "Can't setup argument for type", type);
1315 #endif  /* SXEMACS */
1316         }
1317 }
1318
1319 static int
1320 ffi_call_using_libffi(Lisp_Object fo_fun, Lisp_Object ret_fo,
1321                       int in_nargs, Lisp_Object *in_args)
1322 {
1323         Lisp_EffiObject *ffio;
1324         Lisp_Object fft;
1325         ffi_cif cif;
1326         ffi_type *rtype;
1327         void *rvalue;
1328         int i;
1329
1330         lf_cindex = in_nargs;           /* reserve */
1331         for (i = 0; i < in_nargs; i++) {
1332                 ffio = XEFFIO(in_args[i]);
1333                 fft = Fffi_canonicalise_type(ffio->type);
1334                 extffi_setup_argument(fft, &ex_ffitypes[i]);
1335                 if (FFI_TPTR(fft))
1336                         ex_values[i] = &ffio->fop.ptr;
1337                 else
1338                         ex_values[i] = ffio->fop.ptr;
1339         }
1340
1341         ffio = XEFFIO(ret_fo);
1342         fft = Fffi_canonicalise_type(ffio->type);
1343         extffi_setup_argument(fft, &rtype);
1344         if (FFI_TPTR(fft))
1345                 rvalue = &ffio->fop.ptr;
1346         else
1347                 rvalue = ffio->fop.ptr;
1348
1349         if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, in_nargs,
1350                          rtype, ex_ffitypes) == FFI_OK)
1351         {
1352                 stop_async_timeouts();
1353                 ffi_call(&cif, (void(*)(void))XEFFIO(fo_fun)->fop.fun, rvalue,
1354                          ex_values);
1355                 start_async_timeouts();
1356                 return 0;
1357         }
1358
1359         /* FAILURE */
1360         return 1;
1361 }
1362 #endif  /* HAVE_LIBFFI */
1363
1364 DEFUN("ffi-call-function", Fffi_call_function, 1, MANY, 0, /*
1365 Call a function referred to by FO with arguments ARGS, maybe
1366 return a foreign object with the result or nil if there is
1367 none.
1368
1369 Arguments are: FO &rest FO-ARGS
1370
1371 FO should be a foreign binding initiated by `ffi-defun', and
1372 ARGS should be foreign data objects or pointers to these.
1373 */
1374       (int nargs, Lisp_Object * args))
1375 {
1376         Lisp_Object faf = Qnil, retfo = Qnil;
1377         Lisp_EffiObject *ffio;
1378         int ret = -1;
1379         struct gcpro gcpro1, gcpro2;
1380
1381         GCPRO2(faf, retfo);
1382
1383         faf =  args[0];
1384         ffio = XEFFIO(faf);
1385         retfo = Fmake_ffi_object(XCAR(XCDR(ffio->type)), Qnil);
1386
1387 #ifdef HAVE_LIBFFI
1388         ret = ffi_call_using_libffi(args[0], retfo, nargs-1, &args[1]);
1389 #endif  /* HAVE_LIBFFI */
1390
1391         RETURN_UNGCPRO(ret == 0 ? retfo : Qnil);
1392 }
1393
1394 #ifdef EF_USE_ASYNEQ
1395 /* handler for asynchronously calling ffi code */
1396 Lisp_Object Qffi_jobp;
1397 #define EFFI_DEBUG_JOB(args...)
1398 static Lisp_Object
1399 exec_sentinel_unwind(Lisp_Object SXE_UNUSED(datum))
1400 {
1401         return Qnil;
1402 }
1403
1404 static inline void
1405 exec_sentinel(void *job, ffi_job_t ffij)
1406         __attribute__((always_inline));
1407 static inline void
1408 exec_sentinel(void *job, ffi_job_t ffij)
1409 {
1410         /* This function can GC */
1411         /* called from main thread */
1412         int speccount = specpdl_depth(), nargs = ffij->sntnl_nargs, i;
1413         Lisp_Object funcell[nargs+2];
1414         struct gcpro gcpro1;
1415
1416         funcell[0] = ffij->sntnl;
1417         funcell[1] = (Lisp_Object)job;
1418         for (i = 0; i < nargs; i++) {
1419                 funcell[2+i] = ffij->sntnl_args[i];
1420         }
1421         GCPROn(funcell, nargs+2);
1422
1423         record_unwind_protect(exec_sentinel_unwind, Qnil);
1424         /* call the funcell */
1425         Ffuncall(nargs+2, funcell);
1426         /* reset to previous state */
1427         restore_match_data();
1428         UNGCPRO;
1429         unbind_to(speccount, Qnil);
1430         return;
1431 }
1432
1433 static inline ffi_job_t
1434 allocate_ffi_job(void)
1435 {
1436         ffi_job_t ffij = xnew(struct ffi_job_s);
1437         EFFI_DEBUG_JOB("allocated: 0x%lx\n", (long unsigned int)ffij);
1438         return ffij;
1439 }
1440
1441 static inline ffi_job_t
1442 make_ffi_job(Lisp_Object fof, int fof_nargs, Lisp_Object *fof_args,
1443              Lisp_Object sntnl, int sntnl_nargs, Lisp_Object *sntnl_args)
1444 {
1445 /* exec'd in the main thread */
1446         ffi_job_t ffij = allocate_ffi_job();
1447         int i;
1448
1449         SXE_MUTEX_INIT(&ffij->mtx);
1450         ffij->fof = fof;
1451         if (fof_nargs > 0) {
1452                 ffij->fof_nargs = fof_nargs;
1453                 ffij->fof_args = xnew_array(Lisp_Object, fof_nargs);
1454                 for (i = 0; i < fof_nargs; i++) {
1455                         ffij->fof_args[i] = fof_args[i];
1456                 }
1457         } else {
1458                 ffij->fof_nargs = 0;
1459                 ffij->fof_args = NULL;
1460         }
1461
1462         ffij->sntnl = sntnl;
1463         if (sntnl_nargs > 0) {
1464                 ffij->sntnl_nargs = sntnl_nargs;
1465                 ffij->sntnl_args = xnew_array(Lisp_Object, sntnl_nargs);
1466                 for (i = 0; i < sntnl_nargs; i++) {
1467                         ffij->sntnl_args[i] = sntnl_args[i];
1468                 }
1469         } else {
1470                 ffij->sntnl_nargs = 0;
1471                 ffij->sntnl_args = NULL;
1472         }
1473
1474         ffij->result = Qnil;
1475         ffij->retfo = Fmake_ffi_object(XCAR(XCDR(XEFFIO(fof)->type)), Qnil);
1476         return ffij;
1477 }
1478
1479 static void
1480 mark_ffi_job(worker_job_t job)
1481 {
1482         ffi_job_t ffij = ffi_job(job);
1483         int i;
1484
1485         if (!ffij)
1486                 return;
1487
1488         SXE_MUTEX_LOCK(&ffij->mtx);
1489         mark_object(ffij->fof);
1490         for (i = 0; i < ffij->fof_nargs; i++) {
1491                 mark_object(ffij->fof_args[i]);
1492         }
1493         mark_object(ffij->sntnl);
1494         for (i = 0; i < ffij->sntnl_nargs; i++) {
1495                 mark_object(ffij->sntnl_args[i]);
1496         }
1497         mark_object(ffij->retfo);
1498         mark_object(ffij->result);
1499         SXE_MUTEX_UNLOCK(&ffij->mtx);
1500         return;
1501 }
1502
1503 static void
1504 print_ffi_job(worker_job_t job, Lisp_Object pcf)
1505 {
1506         ffi_job_t ffij = ffi_job(job);
1507
1508         SXE_MUTEX_LOCK(&ffij->mtx);
1509         WRITE_FMT_STRING(pcf, " carrying  #<ffi-job 0x%lx>", 
1510                          (long unsigned int)ffij);
1511         SXE_MUTEX_UNLOCK(&ffij->mtx);
1512         return;
1513 }
1514
1515 static inline void
1516 finish_ffi_job_data(ffi_job_t ffij)
1517 {
1518         SXE_MUTEX_LOCK(&ffij->mtx);
1519         xfree(ffij->fof_args);
1520         xfree(ffij->sntnl_args);
1521         SXE_MUTEX_UNLOCK(&ffij->mtx);
1522         SXE_MUTEX_FINI(&ffij->mtx);
1523
1524         EFFI_DEBUG_JOB("finished: 0x%lx\n", (long unsigned int)ffij);
1525         xfree(ffij);
1526 }
1527
1528 static void
1529 finish_ffi_job(worker_job_t job)
1530 {
1531         ffi_job_t ffij;
1532
1533         lock_worker_job(job);
1534         ffij = ffi_job(job);
1535
1536         if (ffij) {
1537                 finish_ffi_job_data(ffij);
1538         }
1539         worker_job_data(job) = NULL;
1540         unlock_worker_job(job);
1541         return;
1542 }
1543
1544 static void
1545 ffi_job_handle(worker_job_t job)
1546 {
1547         /* thread-safe */
1548         /* usually called from aux threads */
1549         ffi_job_t ffij;
1550         Lisp_Object fof = Qnil, retfo = Qnil, *args = NULL;
1551         int nargs, ret = -1;
1552
1553         lock_worker_job(job);
1554         ffij = ffi_job(job);
1555         unlock_worker_job(job);
1556         SXE_MUTEX_LOCK(&ffij->mtx);
1557         fof = ffij->fof;
1558         nargs = ffij->fof_nargs;
1559         args = ffij->fof_args;
1560         SXE_MUTEX_UNLOCK(&ffij->mtx);
1561
1562         /* can't ... Fmake_ffi_object is not mt-safe */
1563         /* retfo = Fmake_ffi_object(XCAR(XCDR(XEFFIO(fof)->type)), Qnil); */
1564         retfo = ffij->retfo;
1565
1566 #ifdef HAVE_LIBFFI
1567         ret = ffi_call_using_libffi(fof, retfo, nargs, args);
1568 #endif  /* HAVE_LIBFFI */
1569         if (ret == 0) {
1570                 SXE_MUTEX_LOCK(&ffij->mtx);
1571                 ffij->result = retfo;
1572                 SXE_MUTEX_UNLOCK(&ffij->mtx);
1573         }
1574
1575         EFFI_DEBUG_JOB("job 0x%lx succeeded\n", (long unsigned int)ffij);
1576         return;
1577 }
1578
1579 static void
1580 ffi_job_finished(worker_job_t job)
1581 {
1582         if (NILP(ffi_job_sentinel(job) /* sentinel */)) {
1583                 return;
1584         }
1585         /* called from main thread */
1586         exec_sentinel(job, ffi_job(job));
1587         return;
1588 }
1589
1590 static struct work_handler_s ffi_job_handler = {
1591         mark_ffi_job, print_ffi_job, finish_ffi_job,
1592         ffi_job_handle, NULL, ffi_job_finished
1593 };
1594
1595 static Lisp_Object
1596 make_ffi_asyneq_job(ffi_job_t ffij)
1597 {
1598         /* create a job digestible by the asyneq */
1599         Lisp_Object job = Qnil;
1600         struct gcpro gcpro1;
1601
1602         GCPRO1(job);
1603         job = wrap_object(make_worker_job(&ffi_job_handler));
1604         XWORKER_JOB_DATA(job) = ffij;
1605         /* the scratch buffer thingie */
1606         UNGCPRO;
1607         return job;
1608 }
1609
1610 DEFUN("ffi-call-function&", Fffi_call_functionX, 1, MANY, 0, /*
1611 Call a function referred to by FO with arguments ARGS asynchronously,
1612 return a job object.
1613
1614 Arguments are: FO &rest FO-ARGS &aux SENTINEL &rest SENTINEL-ARGS
1615
1616 FO should be a foreign binding initiated by `ffi-defun'.
1617 FO-ARGS should be exactly as many foreign data objects as FO needs.
1618 SENTINEL is a lisp sentinel function called when the job finished,
1619   the function should take at least one argument JOB, further arguments
1620   may be specified by passing further SENTINEL-ARGS.
1621 */
1622       (int nargs, Lisp_Object *args))
1623 {
1624         Lisp_Object job = Qnil;
1625         Lisp_Object sntnl, fof, *sntnl_args, *fof_args;
1626         int sntnl_nargs, fof_nargs;
1627         ffi_job_t ffij;
1628         struct gcpro gcpro1, gcpro2;
1629
1630         CHECK_EFFIO(args[0]);
1631         GCPRO1n(job, args, nargs);
1632
1633         fof = args[0];
1634         /* determine how many args belong to the fof */
1635         fof_nargs = XINT(Flength(XCDR(XEFFIO(fof)->type)))-1;
1636         fof_args = &args[1];
1637
1638         if ((sntnl_nargs = nargs - fof_nargs - 2) >= 0) {
1639                 sntnl = args[fof_nargs+1];
1640                 sntnl_args = &args[fof_nargs+2];
1641         } else {
1642                 sntnl = Qnil;
1643                 sntnl_args = NULL;
1644         }
1645
1646         /* create the job data object */
1647         ffij = make_ffi_job(fof, fof_nargs, fof_args,
1648                             sntnl, sntnl_nargs, sntnl_args);
1649         /* now prepare the job to dispatch */
1650         job = make_ffi_asyneq_job(ffij);
1651         /* ... and dispatch it, change its state to queued */
1652         XWORKER_JOB_STATE(job) = WORKER_JOB_QUEUED;
1653         eq_enqueue(delegate_eq, job);
1654         /* brag about new jobs in the queue */
1655         eq_queue_trigger_all(delegate_eq);
1656
1657         UNGCPRO;
1658         return job;
1659 }
1660 #endif  /* EF_USE_ASYNEQ */
1661
1662 extern struct device *decode_x_device(Lisp_Object device);
1663
1664 DEFUN("x-device-display", Fx_device_display, 0, 1, 0,   /*
1665 Return DEVICE display as FFI object.
1666 */
1667       (device))
1668 {
1669 #if HAVE_X_WINDOWS
1670         Lisp_Object fo;
1671
1672         fo = Fmake_ffi_object(Q_pointer, Qnil);
1673         XEFFIO(fo)->fotype = EFFI_FOT_BIND;
1674         XEFFIO(fo)->fop.ptr = (void*)DEVICE_X_DISPLAY(decode_x_device(device));
1675         return fo;
1676 #else
1677         return Qnil;
1678 #endif
1679 }
1680
1681 /* Callbacks */
1682 #define FFI_CC_CDECL 0
1683
1684 #if defined __i386__
1685 static void
1686 ffi_callback_call_x86(Lisp_Object cbk_info, char *arg_buffer)
1687 {
1688         Lisp_Object fun, alist = Qnil, retlo, foret;
1689         Lisp_Object rtype, argtypes;
1690         struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
1691         void *ptr;
1692
1693         fun = Fcar(cbk_info);
1694         rtype = Fcar(Fcdr(cbk_info));
1695         argtypes = Fcar(Fcdr(Fcdr(cbk_info)));
1696
1697         CHECK_LIST(argtypes);
1698
1699         arg_buffer += 4;                /* Skip return address */
1700         while (!NILP(argtypes)) {
1701                 Lisp_Object result, ctype;
1702                 int size;
1703  
1704                 ctype = ffi_canonicalise_type(XCAR(argtypes));
1705                 size = XINT(Fffi_size_of_type(ctype));
1706                 if (EQ(ctype, Q_c_string)) {
1707                         char *aptr = *(char**)arg_buffer;
1708                         if (aptr)
1709                                 result = ffi_fetch_foreign(aptr, ctype);
1710                         else
1711                                 result = Qnil;
1712                 } else
1713                         result = ffi_fetch_foreign(arg_buffer, ctype);
1714                 /* Apply translators and put the result into alist */
1715                 result = apply1(Findirect_function(Qffi_translate_from_foreign),
1716                                 list2(result, XCAR(argtypes)));
1717                 alist = Fcons(result, alist);
1718                 {
1719                         int mask = 3;
1720                         int sp = (size + mask) & ~mask;
1721                         arg_buffer += (sp);
1722                 }
1723                 argtypes = XCDR(argtypes);
1724         }
1725         alist = Fnreverse(alist);
1726
1727         /* Special case, we have no return value */
1728         if (EQ(rtype, Q_void)) {
1729                 GCPRO3(fun, alist, rtype);
1730                 apply1(fun, alist);
1731                 UNGCPRO;
1732                 return;
1733         }
1734
1735         GCPRO5(fun, alist, rtype, retlo, foret);
1736         retlo = apply1(fun, alist);
1737         foret = Fmake_ffi_object(rtype, Qnil);
1738         Fffi_store(foret, make_int(0), rtype, retlo);
1739         ptr = (void*)XEFFIO(foret)->fop.ptr;
1740         if (EQ(rtype, Q_double)) {
1741                 UNGCPRO;
1742                 {
1743                 asm volatile ("fldl (%0)" :: "a" (ptr));
1744                 }
1745                 return;
1746         } else if (EQ(rtype, Q_float)) {
1747                 UNGCPRO;
1748                 {
1749                 asm volatile ("flds (%0)" :: "a" (ptr));
1750                 }
1751                 return;
1752         } else {
1753                 int iv;
1754
1755                 if (EQ(rtype, Q_byte) || EQ(rtype, Q_char))
1756                         iv = *(char*)ptr;
1757                 else if (EQ(rtype, Q_unsigned_byte) || EQ(rtype, Q_unsigned_char))
1758                         iv = *(char unsigned*)ptr;
1759                 else if (EQ(rtype, Q_short))
1760                         iv = *(short*)ptr;
1761                 else if (EQ(rtype, Q_unsigned_short))
1762                         iv = *(unsigned short*)ptr;
1763                 else
1764                         iv = *(int*)ptr;
1765                 UNGCPRO;
1766                 {
1767                         asm volatile ("movl %0,%%eax;" :: "r" (iv) : "%eax");
1768                 }
1769                 return;
1770         }
1771 }
1772
1773 void*
1774 ffi_make_callback_x86(Lisp_Object data, int cc_type)
1775 {
1776         /*
1777          *      push    %esp                            54
1778          *      pushl   <data>                          68 <addr32>
1779          *      call    ffi_callback_call_x86           E8 <disp32>
1780          *      pop     %ecx                            59
1781          *      pop     %ecx                            59
1782          *      ret                                     c3
1783          *      nop                                     90
1784          *      nop                                     90
1785          */
1786
1787         char *buf = xmalloc(sizeof(char)*16);
1788         *(char*) (buf+0)  = 0x54;
1789         *(char*) (buf+1)  = 0x68;
1790         *(long*) (buf+2)  = (long)data;
1791         *(char*) (buf+6)  = 0xE8;
1792         *(long*) (buf+7)  = (long)ffi_callback_call_x86 - (long)(buf+11);
1793         *(char*) (buf+11) = 0x59;
1794         *(char*) (buf+12) = 0x59;
1795         if (cc_type == FFI_CC_CDECL) {
1796                 *(char*) (buf+13) = 0xc3;
1797                 *(short*)(buf+14) = 0x9090;
1798         } else {
1799                 Lisp_Object arg_types = Fcar(Fcdr(Fcdr(data)));
1800                 int byte_size = 0;
1801                 int mask = 3;
1802
1803                 CHECK_CONS(arg_types);
1804
1805                 while (!NILP(arg_types)) {
1806                         int sz = XINT(Fffi_size_of_type(XCAR(arg_types)));
1807                         byte_size += ((sz+mask)&(~mask));
1808                         arg_types = XCDR(arg_types);
1809                 }
1810
1811                 *(char*) (buf+13) = 0xc2;
1812                 *(short*)(buf+14) = (short)byte_size;
1813         }
1814
1815         return buf;
1816 }
1817 #endif  /* __i386__ */
1818
1819 DEFUN("ffi-make-callback", Fffi_make_callback, 4, 4, 0, /*
1820 Create dynamic callback and return pointer to it.
1821 */
1822       (fun, rtype, argtypes, cctype))
1823 {
1824         Lisp_Object data;
1825         Lisp_Object ptr;
1826
1827         CHECK_INT(cctype);
1828
1829         data = list3(fun, rtype, argtypes);
1830         /* Put data as property of the fun, so it(data) wont be GCed */
1831         Fput(fun, Q_ffi_callback, data);
1832         ptr = Fmake_ffi_object(Q_pointer, Qnil);
1833 #ifdef __i386__
1834         XEFFIO(ptr)->fop.ptr = ffi_make_callback_x86(data, XINT(cctype));
1835 #endif /* __i386__ */
1836         return ptr;
1837 }
1838
1839 void
1840 syms_of_ffi(void)
1841 {
1842         INIT_LRECORD_IMPLEMENTATION(ffiobject);
1843
1844         defsymbol(&Q_byte, "byte");
1845         defsymbol(&Q_unsigned_byte, "unsigned-byte");
1846         defsymbol(&Q_char, "char");
1847         defsymbol(&Q_unsigned_char, "unsigned-char");
1848         defsymbol(&Q_short, "short");
1849         defsymbol(&Q_unsigned_short, "unsigned-short");
1850         defsymbol(&Q_int, "int");
1851         defsymbol(&Q_unsigned_int, "unsigned-int");
1852         defsymbol(&Q_long, "long");
1853         defsymbol(&Q_unsigned_long, "unsigned-long");
1854         defsymbol(&Q_float, "float");
1855         defsymbol(&Q_double, "double");
1856         defsymbol(&Q_void, "void");
1857         defsymbol(&Q_pointer, "pointer");
1858         defsymbol(&Q_struct, "struct");
1859         defsymbol(&Q_union, "union");
1860         defsymbol(&Q_array, "array");
1861         defsymbol(&Q_function, "function");
1862         defsymbol(&Q_c_string, "c-string");
1863         defsymbol(&Q_c_data, "c-data");
1864
1865         defsymbol(&Qffiobjectp, "ffiobjectp");
1866
1867         defsymbol(&Qffi_translate_to_foreign, "ffi-translate-to-foreign");
1868         defsymbol(&Qffi_translate_from_foreign, "ffi-translate-from-foreign");
1869
1870         defsymbol(&Q_ffi_callback, "ffi-callback");
1871
1872         DEFSUBR(Fffi_basic_type_p);
1873         DEFSUBR(Fffi_canonicalise_type);
1874         DEFSUBR(Fffi_size_of_type);
1875         DEFSUBR(Fmake_ffi_object);
1876         DEFSUBR(Fffi_object_p);
1877         DEFSUBR(Fffi_make_pointer);
1878         DEFSUBR(Fffi_object_address);
1879         DEFSUBR(Fffi_object_canonical_type);
1880         DEFSUBR(Fffi_object_type);
1881         DEFSUBR(Fffi_object_size);
1882         DEFSUBR(Fffi_set_storage_size);
1883         DEFSUBR(Fffi_set_object_type);
1884         DEFSUBR(Fffi_fetch);
1885         DEFSUBR(Fffi_aref);
1886         DEFSUBR(Fffi_store);
1887         DEFSUBR(Fffi_aset);
1888         DEFSUBR(Fffi_address_of);
1889         DEFSUBR(Fffi_type_alignment);
1890         DEFSUBR(Fffi_slot_offset);
1891         DEFSUBR(Fffi_load_library);
1892         DEFSUBR(Fffi_bind);
1893         DEFSUBR(Fffi_dlerror);
1894         DEFSUBR(Fffi_defun);
1895         DEFSUBR(Fffi_call_function);
1896
1897         DEFSUBR(Fffi_lisp_object_to_pointer);
1898         DEFSUBR(Fffi_pointer_to_lisp_object);
1899         DEFSUBR(Fffi_plist);
1900
1901 #ifdef EF_USE_ASYNEQ
1902         DEFSUBR(Fffi_call_functionX);
1903         defsymbol(&Qffi_jobp, "ffi-job-p");
1904 #endif
1905
1906         DEFSUBR(Fx_device_display);
1907
1908         DEFSUBR(Fffi_make_callback);
1909 }
1910
1911 void
1912 reinit_vars_of_ffi(void)
1913 {
1914         staticpro_nodump(&Vffi_all_objects);
1915         Vffi_all_objects = make_weak_list(WEAK_LIST_SIMPLE);
1916 }
1917
1918 void
1919 vars_of_ffi(void)
1920 {
1921         reinit_vars_of_ffi();
1922
1923         DEFVAR_LISP("ffi-named-types", &Vffi_named_types        /*
1924 Alist of named FFI types with elements of the form (NAME . FFI-TYPE).
1925                                                  */ );
1926         Vffi_named_types = Qnil;
1927
1928         DEFVAR_LISP("ffi-loaded-libraries", &Vffi_loaded_libraries /*
1929 Alist of loaded libraries with elements of the form (LIB-NAME . FFIO).
1930                                                  */ );
1931         Vffi_loaded_libraries = Qnil;
1932
1933         DEFVAR_LISP("ffi-type-checker", &Vffi_type_checker /*
1934 Function to call when the validity of an FFI type shall be checked.
1935                                                            */ );
1936         Vffi_type_checker = intern("ffi-type-p");
1937 }