Merge branch 'njsf-cov' into for-steve
[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 = NULL;
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                 if ( tmp != NULL ) {
1067                              memcpy((char*)ptr, tmp, tmplen + 1);
1068                 }
1069 #else
1070                 memcpy((char*)ptr,
1071                        (const char *)XSTRING_DATA(val),
1072                        XSTRING_LENGTH(val) + 1);
1073 #endif
1074         } else if (EQ(val_type, Q_c_data) ||
1075                    (CONSP(val_type) &&
1076                     EQ(XCAR(val_type), Q_c_data) && INTP(XCDR(val_type)))) {
1077                 char *val_ext = NULL;
1078                 unsigned int val_ext_len;
1079                 if (!STRINGP(val))
1080                         SIGNAL_ERROR(Qwrong_type_argument, list2(Qstringp, val));
1081
1082                 TO_EXTERNAL_FORMAT(LISP_STRING, val, ALLOCA,
1083                                    (val_ext, val_ext_len), Qbinary);
1084                 if (val_ext == NULL || 
1085                     (CONSP(val_type) && (val_ext_len > XINT(XCDR(val_type))))) {
1086 #ifdef SXEMACS
1087                         error("storage size too small");
1088 #else
1089                         Fsignal(Qrange_error,
1090                                 list2(Qstringp,
1091                                       build_string("storage size too small")));
1092 #endif  /* SXEMACS */
1093                 } else {
1094                         memcpy((char*)ptr, (const char *)val_ext, val_ext_len);
1095                 }
1096         } else if (FFI_POINTERP(val_type)) {
1097                 if (!EFFIOP(val)) {
1098 #ifdef SXEMACS
1099                         signal_simple_error("FFI: Value not of pointer type", \
1100                                             list2(origtype, val));
1101 #else
1102                         Fsignal(Qwrong_type_argument,
1103                                 list2(Qstringp, build_string("type")));
1104 #endif  /* SXEMACS */
1105                 }
1106                 *(void**)ptr = (void*)XEFFIO(val)->fop.ptr;
1107         } else if (CONSP(val_type) && EQ(XCAR(val_type), Q_struct)) {
1108                 if (!EFFIOP(val)) {
1109 #ifdef SXEMACS
1110                         signal_simple_error("FFI: Value not FFI object", \
1111                                             list2(origtype, val));
1112 #else
1113                         Fsignal(Qwrong_type_argument,
1114                                 list2(Qstringp, build_string("type")));
1115 #endif  /* SXEMACS */
1116                 }
1117                 memcpy((char*)ptr, (const char *)XEFFIO(val)->fop.ptr, \
1118                        XINT(Fffi_size_of_type(val_type)));
1119         } else {
1120 #ifdef SXEMACS
1121                 signal_simple_error("FFI: Non basic or pointer type", origtype);
1122 #else
1123                 Fsignal(Qinternal_error,
1124                         list2(Qstringp,
1125                               build_string("non basic or pointer type")));
1126 #endif  /* SXEMACS */
1127         }
1128
1129         return val;
1130 }
1131
1132 DEFUN("ffi-aset", Fffi_aset, 3, 3, 0, /*
1133 Store the element VALUE in FARRAY at index IDX (starting with 0).
1134 */
1135       (farray, idx, value))
1136 {
1137         Lisp_Object type;
1138         
1139         CHECK_EFFIO(farray);
1140         CHECK_INT(idx);
1141         
1142         type = ffi_canonicalise_type(XEFFIO(farray)->type);
1143         if (!FFI_TPTR(type)) {
1144 #ifdef SXEMACS
1145                 signal_simple_error("Not an array type", type);
1146 #else
1147                 signal_error(Qinternal_error, "Not an array type", type);
1148 #endif  /* SXEMACS */
1149         }
1150         if (EQ(type, Q_c_string))
1151                 type = Q_char;
1152         else
1153                 type = Fcar(XCDR(type));
1154
1155         return Fffi_store(farray,
1156                           make_int(XINT(Fffi_size_of_type(type)) * XINT(idx)),
1157                           type, value);
1158 }
1159
1160 DEFUN("ffi-address-of", Fffi_address_of, 1, 1, 0, /*
1161 Return the FFI object that stores the address of given FFI object FO.
1162
1163 This is the equivalent of the `&' operator in C.
1164 */
1165       (fo))
1166 {
1167         Lisp_Object newfo = Qnil;
1168         Lisp_EffiObject *ffio, *newffio;
1169         struct gcpro gcpro1;
1170
1171         CHECK_EFFIO(fo);
1172         ffio = XEFFIO(fo);
1173
1174         GCPRO1(newfo);
1175         newfo = Fmake_ffi_object(Q_pointer, Qnil);
1176         newffio = XEFFIO(newfo);
1177
1178         newffio->fotype = EFFI_FOT_BIND;
1179         if (FFI_TPTR(ffio->type))
1180                 newffio->fop.ptr = (void*)&ffio->fop.ptr;
1181         else
1182                 newffio->fop.ptr = ffio->fop.ptr;
1183
1184         RETURN_UNGCPRO(newfo);
1185 }
1186
1187 DEFUN("ffi-lisp-object-to-pointer", Fffi_lisp_object_to_pointer, 1, 1, 0, /*
1188 Convert lisp object to FFI pointer.
1189 */
1190       (obj))
1191 {
1192         Lisp_Object newfo = Qnil;
1193         Lisp_EffiObject *newffio;
1194         struct gcpro gcpro1;
1195
1196         GCPRO1(obj);
1197
1198         newfo = Fmake_ffi_object(Q_pointer, Qnil);
1199         newffio = XEFFIO(newfo);
1200         newffio->fotype = EFFI_FOT_BIND;
1201         newffio->fop.ptr = (void*)obj;
1202
1203         /* Hold a reference to OBJ in NEWFO's plist */
1204         Fput(newfo, intern("lisp-object"), obj);
1205
1206         RETURN_UNGCPRO(newfo);
1207 }
1208
1209 DEFUN("ffi-pointer-to-lisp-object", Fffi_pointer_to_lisp_object, 1, 1, 0, /*
1210 Convert FFI pointer to lisp object.
1211 */
1212       (ptr))
1213 {
1214         CHECK_EFFIO(ptr);
1215         return (Lisp_Object)XEFFIO(ptr)->fop.ptr;
1216 }
1217
1218 DEFUN("ffi-plist", Fffi_plist, 1, 1, 0, /*
1219 Return properties list for FFI object FO.
1220 */
1221       (fo))
1222 {
1223         CHECK_EFFIO(fo);
1224         return (XEFFIO(fo)->plist);
1225 }
1226
1227 #ifdef HAVE_LIBFFI
1228
1229 static int lf_cindex = 0;
1230
1231 /*
1232  * XXX
1233  *  This will work in most cases.
1234  *  However it might not work for large structures,
1235  *  In general we should allocate these spaces dynamically
1236  */
1237 #define MAX_TYPES_VALUES 1024
1238 /* ex_ffitypes_dummies used for structure types */
1239 static ffi_type ex_ffitypes_dummies[MAX_TYPES_VALUES + 1];
1240 static ffi_type *ex_ffitypes[MAX_TYPES_VALUES + 1];
1241 static void *ex_values[MAX_TYPES_VALUES + 1];
1242
1243 #if SIZEOF_LONG == 4
1244 #  define effi_type_ulong ffi_type_uint32
1245 #  define effi_type_slong ffi_type_sint32
1246 #elif SIZEOF_LONG == 8
1247 #  define effi_type_ulong ffi_type_uint64
1248 #  define effi_type_slong ffi_type_sint64
1249 #endif
1250
1251 static void
1252 extffi_setup_argument(Lisp_Object type, ffi_type **ft)
1253 {
1254         type = ffi_canonicalise_type(type);
1255         if (EQ(type, Q_char) || EQ(type, Q_byte))
1256                 *ft = &ffi_type_schar;
1257         else if (EQ(type, Q_unsigned_char) || EQ(type, Q_unsigned_byte))
1258                 *ft = &ffi_type_uchar;
1259         else if (EQ(type, Q_short))
1260                 *ft = &ffi_type_sshort;
1261         else if (EQ(type, Q_unsigned_short))
1262                 *ft = &ffi_type_ushort;
1263         else if (EQ(type, Q_int))
1264                 *ft = &ffi_type_sint;
1265         else if (EQ(type, Q_unsigned_int))
1266                 *ft = &ffi_type_uint;
1267         else if (EQ(type, Q_unsigned_long))
1268                 *ft = &effi_type_ulong;
1269         else if (EQ(type, Q_long))
1270                 *ft = &effi_type_slong;
1271         else if (EQ(type, Q_float))
1272                 *ft = &ffi_type_float;
1273         else if (EQ(type, Q_double))
1274                 *ft = &ffi_type_double;
1275         else if (EQ(type, Q_void))
1276                 *ft = &ffi_type_void;
1277         else if (FFI_TPTR(type))
1278                 *ft = &ffi_type_pointer;
1279         else if (CONSP(type) && EQ(XCAR(type), Q_struct)) {
1280                 Lisp_Object slots = Fcdr(XCDR(type));
1281                 ffi_type **ntypes;
1282                 int nt_size, i;
1283
1284                 CHECK_CONS(slots);
1285
1286                 nt_size = XINT(Flength(slots)) + 1;
1287                 if (nt_size + lf_cindex > MAX_TYPES_VALUES) {
1288                         lf_cindex = 0;  /* reset cindex */
1289 #ifdef SXEMACS
1290                         error("cindex overflow");
1291 #else
1292                         Fsignal(Qoverflow_error,
1293                                 list2(Qstringp,
1294                                       build_string("cindex overflow")));
1295 #endif  /* SXEMACS */
1296                 }
1297                 ntypes = &ex_ffitypes[lf_cindex];
1298                 *ft = &ex_ffitypes_dummies[lf_cindex];
1299
1300                 /* Update lf_cindex in case TYPE struct contains other
1301                  * structures */
1302                 lf_cindex += nt_size;
1303
1304                 (*ft)->type = FFI_TYPE_STRUCT;
1305                 (*ft)->alignment = ffi_type_align(type);
1306                 (*ft)->elements = ntypes;
1307
1308                 for (i = 0; (i < nt_size) && !NILP(slots); slots = XCDR(slots), i++)
1309                         extffi_setup_argument(Fcar(Fcdr(XCAR(slots))), &ntypes[i]);
1310                 ntypes[i] = NULL;
1311         } else {
1312 #ifdef SXEMACS
1313                 signal_simple_error("Can't setup argument for type", type);
1314 #else
1315                 signal_error(Qinternal_error,
1316                              "Can't setup argument for type", type);
1317 #endif  /* SXEMACS */
1318         }
1319 }
1320
1321 static int
1322 ffi_call_using_libffi(Lisp_Object fo_fun, Lisp_Object ret_fo,
1323                       int in_nargs, Lisp_Object *in_args)
1324 {
1325         Lisp_EffiObject *ffio;
1326         Lisp_Object fft;
1327         ffi_cif cif;
1328         ffi_type *rtype;
1329         void *rvalue;
1330         int i;
1331
1332         lf_cindex = in_nargs;           /* reserve */
1333         for (i = 0; i < in_nargs; i++) {
1334                 ffio = XEFFIO(in_args[i]);
1335                 fft = Fffi_canonicalise_type(ffio->type);
1336                 extffi_setup_argument(fft, &ex_ffitypes[i]);
1337                 if (FFI_TPTR(fft))
1338                         ex_values[i] = &ffio->fop.ptr;
1339                 else
1340                         ex_values[i] = ffio->fop.ptr;
1341         }
1342
1343         ffio = XEFFIO(ret_fo);
1344         fft = Fffi_canonicalise_type(ffio->type);
1345         extffi_setup_argument(fft, &rtype);
1346         if (FFI_TPTR(fft))
1347                 rvalue = &ffio->fop.ptr;
1348         else
1349                 rvalue = ffio->fop.ptr;
1350
1351         if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, in_nargs,
1352                          rtype, ex_ffitypes) == FFI_OK)
1353         {
1354                 stop_async_timeouts();
1355                 ffi_call(&cif, (void(*)(void))XEFFIO(fo_fun)->fop.fun, rvalue,
1356                          ex_values);
1357                 start_async_timeouts();
1358                 return 0;
1359         }
1360
1361         /* FAILURE */
1362         return 1;
1363 }
1364 #endif  /* HAVE_LIBFFI */
1365
1366 DEFUN("ffi-call-function", Fffi_call_function, 1, MANY, 0, /*
1367 Call a function referred to by FO with arguments ARGS, maybe
1368 return a foreign object with the result or nil if there is
1369 none.
1370
1371 Arguments are: FO &rest FO-ARGS
1372
1373 FO should be a foreign binding initiated by `ffi-defun', and
1374 ARGS should be foreign data objects or pointers to these.
1375 */
1376       (int nargs, Lisp_Object * args))
1377 {
1378         Lisp_Object faf = Qnil, retfo = Qnil;
1379         Lisp_EffiObject *ffio;
1380         int ret = -1;
1381         struct gcpro gcpro1, gcpro2;
1382
1383         GCPRO2(faf, retfo);
1384
1385         faf =  args[0];
1386         ffio = XEFFIO(faf);
1387         retfo = Fmake_ffi_object(XCAR(XCDR(ffio->type)), Qnil);
1388
1389 #ifdef HAVE_LIBFFI
1390         ret = ffi_call_using_libffi(args[0], retfo, nargs-1, &args[1]);
1391 #endif  /* HAVE_LIBFFI */
1392
1393         RETURN_UNGCPRO(ret == 0 ? retfo : Qnil);
1394 }
1395
1396 #ifdef EF_USE_ASYNEQ
1397 /* handler for asynchronously calling ffi code */
1398 Lisp_Object Qffi_jobp;
1399 #define EFFI_DEBUG_JOB(args...)
1400 static Lisp_Object
1401 exec_sentinel_unwind(Lisp_Object SXE_UNUSED(datum))
1402 {
1403         return Qnil;
1404 }
1405
1406 static inline void
1407 exec_sentinel(void *job, ffi_job_t ffij)
1408         __attribute__((always_inline));
1409 static inline void
1410 exec_sentinel(void *job, ffi_job_t ffij)
1411 {
1412         /* This function can GC */
1413         /* called from main thread */
1414         int speccount = specpdl_depth(), nargs = ffij->sntnl_nargs, i;
1415         Lisp_Object funcell[nargs+2];
1416         struct gcpro gcpro1;
1417
1418         funcell[0] = ffij->sntnl;
1419         funcell[1] = (Lisp_Object)job;
1420         for (i = 0; i < nargs; i++) {
1421                 funcell[2+i] = ffij->sntnl_args[i];
1422         }
1423         GCPROn(funcell, nargs+2);
1424
1425         record_unwind_protect(exec_sentinel_unwind, Qnil);
1426         /* call the funcell */
1427         Ffuncall(nargs+2, funcell);
1428         /* reset to previous state */
1429         restore_match_data();
1430         UNGCPRO;
1431         unbind_to(speccount, Qnil);
1432         return;
1433 }
1434
1435 static inline ffi_job_t
1436 allocate_ffi_job(void)
1437 {
1438         ffi_job_t ffij = xnew(struct ffi_job_s);
1439         EFFI_DEBUG_JOB("allocated: 0x%lx\n", (long unsigned int)ffij);
1440         return ffij;
1441 }
1442
1443 static inline ffi_job_t
1444 make_ffi_job(Lisp_Object fof, int fof_nargs, Lisp_Object *fof_args,
1445              Lisp_Object sntnl, int sntnl_nargs, Lisp_Object *sntnl_args)
1446 {
1447 /* exec'd in the main thread */
1448         ffi_job_t ffij = allocate_ffi_job();
1449         int i;
1450
1451         SXE_MUTEX_INIT(&ffij->mtx);
1452         ffij->fof = fof;
1453         if (fof_nargs > 0) {
1454                 ffij->fof_nargs = fof_nargs;
1455                 ffij->fof_args = xnew_array(Lisp_Object, fof_nargs);
1456                 for (i = 0; i < fof_nargs; i++) {
1457                         ffij->fof_args[i] = fof_args[i];
1458                 }
1459         } else {
1460                 ffij->fof_nargs = 0;
1461                 ffij->fof_args = NULL;
1462         }
1463
1464         ffij->sntnl = sntnl;
1465         if (sntnl_nargs > 0) {
1466                 ffij->sntnl_nargs = sntnl_nargs;
1467                 ffij->sntnl_args = xnew_array(Lisp_Object, sntnl_nargs);
1468                 for (i = 0; i < sntnl_nargs; i++) {
1469                         ffij->sntnl_args[i] = sntnl_args[i];
1470                 }
1471         } else {
1472                 ffij->sntnl_nargs = 0;
1473                 ffij->sntnl_args = NULL;
1474         }
1475
1476         ffij->result = Qnil;
1477         ffij->retfo = Fmake_ffi_object(XCAR(XCDR(XEFFIO(fof)->type)), Qnil);
1478         return ffij;
1479 }
1480
1481 static void
1482 mark_ffi_job(worker_job_t job)
1483 {
1484         ffi_job_t ffij = ffi_job(job);
1485         int i;
1486
1487         if (!ffij)
1488                 return;
1489
1490         SXE_MUTEX_LOCK(&ffij->mtx);
1491         mark_object(ffij->fof);
1492         for (i = 0; i < ffij->fof_nargs; i++) {
1493                 mark_object(ffij->fof_args[i]);
1494         }
1495         mark_object(ffij->sntnl);
1496         for (i = 0; i < ffij->sntnl_nargs; i++) {
1497                 mark_object(ffij->sntnl_args[i]);
1498         }
1499         mark_object(ffij->retfo);
1500         mark_object(ffij->result);
1501         SXE_MUTEX_UNLOCK(&ffij->mtx);
1502         return;
1503 }
1504
1505 static void
1506 print_ffi_job(worker_job_t job, Lisp_Object pcf)
1507 {
1508         ffi_job_t ffij = ffi_job(job);
1509
1510         SXE_MUTEX_LOCK(&ffij->mtx);
1511         WRITE_FMT_STRING(pcf, " carrying  #<ffi-job 0x%lx>", 
1512                          (long unsigned int)ffij);
1513         SXE_MUTEX_UNLOCK(&ffij->mtx);
1514         return;
1515 }
1516
1517 static inline void
1518 finish_ffi_job_data(ffi_job_t ffij)
1519 {
1520         SXE_MUTEX_LOCK(&ffij->mtx);
1521         xfree(ffij->fof_args);
1522         xfree(ffij->sntnl_args);
1523         SXE_MUTEX_UNLOCK(&ffij->mtx);
1524         SXE_MUTEX_FINI(&ffij->mtx);
1525
1526         EFFI_DEBUG_JOB("finished: 0x%lx\n", (long unsigned int)ffij);
1527         xfree(ffij);
1528 }
1529
1530 static void
1531 finish_ffi_job(worker_job_t job)
1532 {
1533         ffi_job_t ffij;
1534
1535         lock_worker_job(job);
1536         ffij = ffi_job(job);
1537
1538         if (ffij) {
1539                 finish_ffi_job_data(ffij);
1540         }
1541         worker_job_data(job) = NULL;
1542         unlock_worker_job(job);
1543         return;
1544 }
1545
1546 static void
1547 ffi_job_handle(worker_job_t job)
1548 {
1549         /* thread-safe */
1550         /* usually called from aux threads */
1551         ffi_job_t ffij;
1552         Lisp_Object fof = Qnil, retfo = Qnil, *args = NULL;
1553         int nargs, ret = -1;
1554
1555         lock_worker_job(job);
1556         ffij = ffi_job(job);
1557         unlock_worker_job(job);
1558         SXE_MUTEX_LOCK(&ffij->mtx);
1559         fof = ffij->fof;
1560         nargs = ffij->fof_nargs;
1561         args = ffij->fof_args;
1562         SXE_MUTEX_UNLOCK(&ffij->mtx);
1563
1564         /* can't ... Fmake_ffi_object is not mt-safe */
1565         /* retfo = Fmake_ffi_object(XCAR(XCDR(XEFFIO(fof)->type)), Qnil); */
1566         retfo = ffij->retfo;
1567
1568 #ifdef HAVE_LIBFFI
1569         ret = ffi_call_using_libffi(fof, retfo, nargs, args);
1570 #endif  /* HAVE_LIBFFI */
1571         if (ret == 0) {
1572                 SXE_MUTEX_LOCK(&ffij->mtx);
1573                 ffij->result = retfo;
1574                 SXE_MUTEX_UNLOCK(&ffij->mtx);
1575         }
1576
1577         EFFI_DEBUG_JOB("job 0x%lx succeeded\n", (long unsigned int)ffij);
1578         return;
1579 }
1580
1581 static void
1582 ffi_job_finished(worker_job_t job)
1583 {
1584         if (NILP(ffi_job_sentinel(job) /* sentinel */)) {
1585                 return;
1586         }
1587         /* called from main thread */
1588         exec_sentinel(job, ffi_job(job));
1589         return;
1590 }
1591
1592 static struct work_handler_s ffi_job_handler = {
1593         mark_ffi_job, print_ffi_job, finish_ffi_job,
1594         ffi_job_handle, NULL, ffi_job_finished
1595 };
1596
1597 static Lisp_Object
1598 make_ffi_asyneq_job(ffi_job_t ffij)
1599 {
1600         /* create a job digestible by the asyneq */
1601         Lisp_Object job = Qnil;
1602         struct gcpro gcpro1;
1603
1604         GCPRO1(job);
1605         job = wrap_object(make_worker_job(&ffi_job_handler));
1606         XWORKER_JOB_DATA(job) = ffij;
1607         /* the scratch buffer thingie */
1608         UNGCPRO;
1609         return job;
1610 }
1611
1612 DEFUN("ffi-call-function&", Fffi_call_functionX, 1, MANY, 0, /*
1613 Call a function referred to by FO with arguments ARGS asynchronously,
1614 return a job object.
1615
1616 Arguments are: FO &rest FO-ARGS &aux SENTINEL &rest SENTINEL-ARGS
1617
1618 FO should be a foreign binding initiated by `ffi-defun'.
1619 FO-ARGS should be exactly as many foreign data objects as FO needs.
1620 SENTINEL is a lisp sentinel function called when the job finished,
1621   the function should take at least one argument JOB, further arguments
1622   may be specified by passing further SENTINEL-ARGS.
1623 */
1624       (int nargs, Lisp_Object *args))
1625 {
1626         Lisp_Object job = Qnil;
1627         Lisp_Object sntnl, fof, *sntnl_args, *fof_args;
1628         int sntnl_nargs, fof_nargs;
1629         ffi_job_t ffij;
1630         struct gcpro gcpro1, gcpro2;
1631
1632         CHECK_EFFIO(args[0]);
1633         GCPRO1n(job, args, nargs);
1634
1635         fof = args[0];
1636         /* determine how many args belong to the fof */
1637         fof_nargs = XINT(Flength(XCDR(XEFFIO(fof)->type)))-1;
1638         fof_args = &args[1];
1639
1640         if ((sntnl_nargs = nargs - fof_nargs - 2) >= 0) {
1641                 sntnl = args[fof_nargs+1];
1642                 sntnl_args = &args[fof_nargs+2];
1643         } else {
1644                 sntnl = Qnil;
1645                 sntnl_args = NULL;
1646         }
1647
1648         /* create the job data object */
1649         ffij = make_ffi_job(fof, fof_nargs, fof_args,
1650                             sntnl, sntnl_nargs, sntnl_args);
1651         /* now prepare the job to dispatch */
1652         job = make_ffi_asyneq_job(ffij);
1653         /* ... and dispatch it, change its state to queued */
1654         XWORKER_JOB_STATE(job) = WORKER_JOB_QUEUED;
1655         eq_enqueue(delegate_eq, job);
1656         /* brag about new jobs in the queue */
1657         eq_queue_trigger_all(delegate_eq);
1658
1659         UNGCPRO;
1660         return job;
1661 }
1662 #endif  /* EF_USE_ASYNEQ */
1663
1664 extern struct device *decode_x_device(Lisp_Object device);
1665
1666 DEFUN("x-device-display", Fx_device_display, 0, 1, 0,   /*
1667 Return DEVICE display as FFI object.
1668 */
1669       (device))
1670 {
1671 #if HAVE_X_WINDOWS
1672         Lisp_Object fo;
1673
1674         fo = Fmake_ffi_object(Q_pointer, Qnil);
1675         XEFFIO(fo)->fotype = EFFI_FOT_BIND;
1676         XEFFIO(fo)->fop.ptr = (void*)DEVICE_X_DISPLAY(decode_x_device(device));
1677         return fo;
1678 #else
1679         return Qnil;
1680 #endif
1681 }
1682
1683 /* Callbacks */
1684 #define FFI_CC_CDECL 0
1685
1686 #if defined __i386__
1687 static void
1688 ffi_callback_call_x86(Lisp_Object cbk_info, char *arg_buffer)
1689 {
1690         Lisp_Object fun, alist = Qnil, retlo, foret;
1691         Lisp_Object rtype, argtypes;
1692         struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
1693         void *ptr;
1694
1695         fun = Fcar(cbk_info);
1696         rtype = Fcar(Fcdr(cbk_info));
1697         argtypes = Fcar(Fcdr(Fcdr(cbk_info)));
1698
1699         CHECK_LIST(argtypes);
1700
1701         arg_buffer += 4;                /* Skip return address */
1702         while (!NILP(argtypes)) {
1703                 Lisp_Object result, ctype;
1704                 int size;
1705  
1706                 ctype = ffi_canonicalise_type(XCAR(argtypes));
1707                 size = XINT(Fffi_size_of_type(ctype));
1708                 if (EQ(ctype, Q_c_string)) {
1709                         char *aptr = *(char**)arg_buffer;
1710                         if (aptr)
1711                                 result = ffi_fetch_foreign(aptr, ctype);
1712                         else
1713                                 result = Qnil;
1714                 } else
1715                         result = ffi_fetch_foreign(arg_buffer, ctype);
1716                 /* Apply translators and put the result into alist */
1717                 result = apply1(Findirect_function(Qffi_translate_from_foreign),
1718                                 list2(result, XCAR(argtypes)));
1719                 alist = Fcons(result, alist);
1720                 {
1721                         int mask = 3;
1722                         int sp = (size + mask) & ~mask;
1723                         arg_buffer += (sp);
1724                 }
1725                 argtypes = XCDR(argtypes);
1726         }
1727         alist = Fnreverse(alist);
1728
1729         /* Special case, we have no return value */
1730         if (EQ(rtype, Q_void)) {
1731                 GCPRO3(fun, alist, rtype);
1732                 apply1(fun, alist);
1733                 UNGCPRO;
1734                 return;
1735         }
1736
1737         GCPRO5(fun, alist, rtype, retlo, foret);
1738         retlo = apply1(fun, alist);
1739         foret = Fmake_ffi_object(rtype, Qnil);
1740         Fffi_store(foret, make_int(0), rtype, retlo);
1741         ptr = (void*)XEFFIO(foret)->fop.ptr;
1742         if (EQ(rtype, Q_double)) {
1743                 UNGCPRO;
1744                 {
1745                 asm volatile ("fldl (%0)" :: "a" (ptr));
1746                 }
1747                 return;
1748         } else if (EQ(rtype, Q_float)) {
1749                 UNGCPRO;
1750                 {
1751                 asm volatile ("flds (%0)" :: "a" (ptr));
1752                 }
1753                 return;
1754         } else {
1755                 int iv;
1756
1757                 if (EQ(rtype, Q_byte) || EQ(rtype, Q_char))
1758                         iv = *(char*)ptr;
1759                 else if (EQ(rtype, Q_unsigned_byte) || EQ(rtype, Q_unsigned_char))
1760                         iv = *(char unsigned*)ptr;
1761                 else if (EQ(rtype, Q_short))
1762                         iv = *(short*)ptr;
1763                 else if (EQ(rtype, Q_unsigned_short))
1764                         iv = *(unsigned short*)ptr;
1765                 else
1766                         iv = *(int*)ptr;
1767                 UNGCPRO;
1768                 {
1769                         asm volatile ("movl %0,%%eax;" :: "r" (iv) : "%eax");
1770                 }
1771                 return;
1772         }
1773 }
1774
1775 void*
1776 ffi_make_callback_x86(Lisp_Object data, int cc_type)
1777 {
1778         /*
1779          *      push    %esp                            54
1780          *      pushl   <data>                          68 <addr32>
1781          *      call    ffi_callback_call_x86           E8 <disp32>
1782          *      pop     %ecx                            59
1783          *      pop     %ecx                            59
1784          *      ret                                     c3
1785          *      nop                                     90
1786          *      nop                                     90
1787          */
1788
1789         char *buf = xmalloc(sizeof(char)*16);
1790         *(char*) (buf+0)  = 0x54;
1791         *(char*) (buf+1)  = 0x68;
1792         *(long*) (buf+2)  = (long)data;
1793         *(char*) (buf+6)  = 0xE8;
1794         *(long*) (buf+7)  = (long)ffi_callback_call_x86 - (long)(buf+11);
1795         *(char*) (buf+11) = 0x59;
1796         *(char*) (buf+12) = 0x59;
1797         if (cc_type == FFI_CC_CDECL) {
1798                 *(char*) (buf+13) = 0xc3;
1799                 *(short*)(buf+14) = 0x9090;
1800         } else {
1801                 Lisp_Object arg_types = Fcar(Fcdr(Fcdr(data)));
1802                 int byte_size = 0;
1803                 int mask = 3;
1804
1805                 CHECK_CONS(arg_types);
1806
1807                 while (!NILP(arg_types)) {
1808                         int sz = XINT(Fffi_size_of_type(XCAR(arg_types)));
1809                         byte_size += ((sz+mask)&(~mask));
1810                         arg_types = XCDR(arg_types);
1811                 }
1812
1813                 *(char*) (buf+13) = 0xc2;
1814                 *(short*)(buf+14) = (short)byte_size;
1815         }
1816
1817         return buf;
1818 }
1819 #endif  /* __i386__ */
1820
1821 DEFUN("ffi-make-callback", Fffi_make_callback, 4, 4, 0, /*
1822 Create dynamic callback and return pointer to it.
1823 */
1824       (fun, rtype, argtypes, cctype))
1825 {
1826         Lisp_Object data;
1827         Lisp_Object ptr;
1828
1829         CHECK_INT(cctype);
1830
1831         data = list3(fun, rtype, argtypes);
1832         /* Put data as property of the fun, so it(data) wont be GCed */
1833         Fput(fun, Q_ffi_callback, data);
1834         ptr = Fmake_ffi_object(Q_pointer, Qnil);
1835 #ifdef __i386__
1836         XEFFIO(ptr)->fop.ptr = ffi_make_callback_x86(data, XINT(cctype));
1837 #endif /* __i386__ */
1838         return ptr;
1839 }
1840
1841 void
1842 syms_of_ffi(void)
1843 {
1844         INIT_LRECORD_IMPLEMENTATION(ffiobject);
1845
1846         defsymbol(&Q_byte, "byte");
1847         defsymbol(&Q_unsigned_byte, "unsigned-byte");
1848         defsymbol(&Q_char, "char");
1849         defsymbol(&Q_unsigned_char, "unsigned-char");
1850         defsymbol(&Q_short, "short");
1851         defsymbol(&Q_unsigned_short, "unsigned-short");
1852         defsymbol(&Q_int, "int");
1853         defsymbol(&Q_unsigned_int, "unsigned-int");
1854         defsymbol(&Q_long, "long");
1855         defsymbol(&Q_unsigned_long, "unsigned-long");
1856         defsymbol(&Q_float, "float");
1857         defsymbol(&Q_double, "double");
1858         defsymbol(&Q_void, "void");
1859         defsymbol(&Q_pointer, "pointer");
1860         defsymbol(&Q_struct, "struct");
1861         defsymbol(&Q_union, "union");
1862         defsymbol(&Q_array, "array");
1863         defsymbol(&Q_function, "function");
1864         defsymbol(&Q_c_string, "c-string");
1865         defsymbol(&Q_c_data, "c-data");
1866
1867         defsymbol(&Qffiobjectp, "ffiobjectp");
1868
1869         defsymbol(&Qffi_translate_to_foreign, "ffi-translate-to-foreign");
1870         defsymbol(&Qffi_translate_from_foreign, "ffi-translate-from-foreign");
1871
1872         defsymbol(&Q_ffi_callback, "ffi-callback");
1873
1874         DEFSUBR(Fffi_basic_type_p);
1875         DEFSUBR(Fffi_canonicalise_type);
1876         DEFSUBR(Fffi_size_of_type);
1877         DEFSUBR(Fmake_ffi_object);
1878         DEFSUBR(Fffi_object_p);
1879         DEFSUBR(Fffi_make_pointer);
1880         DEFSUBR(Fffi_object_address);
1881         DEFSUBR(Fffi_object_canonical_type);
1882         DEFSUBR(Fffi_object_type);
1883         DEFSUBR(Fffi_object_size);
1884         DEFSUBR(Fffi_set_storage_size);
1885         DEFSUBR(Fffi_set_object_type);
1886         DEFSUBR(Fffi_fetch);
1887         DEFSUBR(Fffi_aref);
1888         DEFSUBR(Fffi_store);
1889         DEFSUBR(Fffi_aset);
1890         DEFSUBR(Fffi_address_of);
1891         DEFSUBR(Fffi_type_alignment);
1892         DEFSUBR(Fffi_slot_offset);
1893         DEFSUBR(Fffi_load_library);
1894         DEFSUBR(Fffi_bind);
1895         DEFSUBR(Fffi_dlerror);
1896         DEFSUBR(Fffi_defun);
1897         DEFSUBR(Fffi_call_function);
1898
1899         DEFSUBR(Fffi_lisp_object_to_pointer);
1900         DEFSUBR(Fffi_pointer_to_lisp_object);
1901         DEFSUBR(Fffi_plist);
1902
1903 #ifdef EF_USE_ASYNEQ
1904         DEFSUBR(Fffi_call_functionX);
1905         defsymbol(&Qffi_jobp, "ffi-job-p");
1906 #endif
1907
1908         DEFSUBR(Fx_device_display);
1909
1910         DEFSUBR(Fffi_make_callback);
1911 }
1912
1913 void
1914 reinit_vars_of_ffi(void)
1915 {
1916         staticpro_nodump(&Vffi_all_objects);
1917         Vffi_all_objects = make_weak_list(WEAK_LIST_SIMPLE);
1918 }
1919
1920 void
1921 vars_of_ffi(void)
1922 {
1923         reinit_vars_of_ffi();
1924
1925         DEFVAR_LISP("ffi-named-types", &Vffi_named_types        /*
1926 Alist of named FFI types with elements of the form (NAME . FFI-TYPE).
1927                                                  */ );
1928         Vffi_named_types = Qnil;
1929
1930         DEFVAR_LISP("ffi-loaded-libraries", &Vffi_loaded_libraries /*
1931 Alist of loaded libraries with elements of the form (LIB-NAME . FFIO).
1932                                                  */ );
1933         Vffi_loaded_libraries = Qnil;
1934
1935         DEFVAR_LISP("ffi-type-checker", &Vffi_type_checker /*
1936 Function to call when the validity of an FFI type shall be checked.
1937                                                            */ );
1938         Vffi_type_checker = intern("ffi-type-p");
1939 }