chiark / gitweb /
Added support for SBCL's native C callbacks, new callback API and improved handling...
[clg] / glib / ffi.lisp
CommitLineData
112ac1d3 1;; Common Lisp bindings for GTK+ v2.x
2;; Copyright 1999-2005 Espen S. Johnsen <espen@users.sf.net>
310da1d5 3;;
112ac1d3 4;; Permission is hereby granted, free of charge, to any person obtaining
5;; a copy of this software and associated documentation files (the
6;; "Software"), to deal in the Software without restriction, including
7;; without limitation the rights to use, copy, modify, merge, publish,
8;; distribute, sublicense, and/or sell copies of the Software, and to
9;; permit persons to whom the Software is furnished to do so, subject to
10;; the following conditions:
310da1d5 11;;
112ac1d3 12;; The above copyright notice and this permission notice shall be
13;; included in all copies or substantial portions of the Software.
310da1d5 14;;
112ac1d3 15;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18;; IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19;; CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20;; TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21;; SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
586328b4 23;; $Id: ffi.lisp,v 1.24 2006-02-19 19:17:45 espen Exp $
310da1d5 24
25(in-package "GLIB")
26
310da1d5 27
28;;;; Foreign function call interface
29
30(defvar *package-prefix* nil)
31
32(defun set-package-prefix (prefix &optional (package *package*))
33 (let ((package (find-package package)))
34 (delete-if #'(lambda (assoc) (eq (car assoc) package)) *package-prefix*)
35 (push (cons package prefix) *package-prefix*))
36 prefix)
37
38(defun package-prefix (&optional (package *package*))
39 (let ((package (find-package package)))
40 (or
41 (cdr (assoc package *package-prefix*))
42 (substitute #\_ #\- (string-downcase (package-name package))))))
43
44(defun find-prefix-package (prefix)
45 (or
46 (car (rassoc (string-downcase prefix) *package-prefix* :test #'string=))
47 (find-package (string-upcase prefix))))
48
49(defmacro use-prefix (prefix &optional (package *package*))
50 `(eval-when (:compile-toplevel :load-toplevel :execute)
51 (set-package-prefix ,prefix ,package)))
52
53
54(defun default-alien-fname (lisp-name)
1ff84b06 55 (let* ((name (substitute #\_ #\- (string-downcase lisp-name)))
56 (stripped-name
57 (cond
58 ((and
59 (char= (char name 0) #\%)
60 (string= "_p" name :start2 (- (length name) 2)))
61 (subseq name 1 (- (length name) 2)))
62 ((char= (char name 0) #\%)
63 (subseq name 1))
64 ((string= "_p" name :start2 (- (length name) 2))
65 (subseq name 0 (- (length name) 2)))
66 (name)))
67 (prefix (package-prefix *package*)))
310da1d5 68 (if (or (not prefix) (string= prefix ""))
1ff84b06 69 stripped-name
70 (format nil "~A_~A" prefix stripped-name))))
310da1d5 71
72(defun default-alien-type-name (type-name)
73 (let ((prefix (package-prefix *package*)))
74 (apply
75 #'concatenate
76 'string
77 (mapcar
78 #'string-capitalize
79 (cons prefix (split-string (symbol-name type-name) #\-))))))
80
81(defun default-type-name (alien-name)
82 (let ((parts
83 (mapcar
84 #'string-upcase
85 (split-string-if alien-name #'upper-case-p))))
86 (intern
87 (concatenate-strings
88 (rest parts) #\-) (find-prefix-package (first parts)))))
89
90
9adccb27 91(defmacro defbinding (name lambda-list return-type &rest docs/args)
310da1d5 92 (multiple-value-bind (lisp-name c-name)
93 (if (atom name)
94 (values name (default-alien-fname name))
95 (values-list name))
96
97 (let ((supplied-lambda-list lambda-list)
98 (docs nil)
99 (args nil))
100 (dolist (doc/arg docs/args)
101 (if (stringp doc/arg)
102 (push doc/arg docs)
103 (progn
104 (destructuring-bind (expr type &optional (style :in)) doc/arg
3840beb2 105 (unless (member style '(:in :out :in-out :return))
310da1d5 106 (error "Bogus argument style ~S in ~S." style doc/arg))
107 (when (and
108 (not supplied-lambda-list)
3840beb2 109 (namep expr) (member style '(:in :in-out :return)))
310da1d5 110 (push expr lambda-list))
7a6c048d 111 (push (list (cond
112 ((and (namep expr) (eq style :out)) expr)
113 ((namep expr) (make-symbol (string expr)))
114 ((gensym)))
115 expr (mklist type) style) args)))))
310da1d5 116
117 (%defbinding
118 c-name lisp-name (or supplied-lambda-list (nreverse lambda-list))
9adccb27 119 return-type (reverse docs) (reverse args)))))
310da1d5 120
73572c12 121#+(or cmu sbcl)
9adccb27 122(defun %defbinding (foreign-name lisp-name lambda-list return-type docs args)
73572c12 123 (collect ((alien-types) (alien-bindings) (alien-parameters)
124 (return-values) (cleanup-forms))
310da1d5 125 (dolist (arg args)
9adccb27 126 (destructuring-bind (var expr type style) arg
127 (let ((declaration (alien-type type))
128 (cleanup (cleanup-form var type)))
129
310da1d5 130 (cond
3840beb2 131 ((member style '(:out :in-out))
132 (alien-types `(* ,declaration))
133 (alien-parameters `(addr ,var))
134 (alien-bindings
135 `(,var ,declaration
fefc2058 136 ,@(cond
137 ((eq style :in-out) (list (to-alien-form expr type)))
138 ((eq declaration 'system-area-pointer)
139 (list '(make-pointer 0))))))
3840beb2 140 (return-values (from-alien-form var type)))
141 ((eq style :return)
142 (alien-types declaration)
143 (alien-bindings
144 `(,var ,declaration ,(to-alien-form expr type)))
145 (alien-parameters var)
146 (return-values (from-alien-form var type)))
147 (cleanup
148 (alien-types declaration)
149 (alien-bindings
150 `(,var ,declaration ,(to-alien-form expr type)))
151 (alien-parameters var)
152 (cleanup-forms cleanup))
153 (t
154 (alien-types declaration)
155 (alien-parameters (to-alien-form expr type)))))))
310da1d5 156
157 (let* ((alien-name (make-symbol (string lisp-name)))
158 (alien-funcall `(alien-funcall ,alien-name ,@(alien-parameters))))
159 `(defun ,lisp-name ,lambda-list
160 ,@docs
73572c12 161 #+cmu(declare (optimize (inhibit-warnings 3)))
162 #+sbcl(declare (muffle-conditions compiler-note))
310da1d5 163 (with-alien ((,alien-name
164 (function
9adccb27 165 ,(alien-type return-type)
310da1d5 166 ,@(alien-types))
167 :extern ,foreign-name)
168 ,@(alien-bindings))
9adccb27 169 ,(if return-type
170 `(values
171 (unwind-protect
172 ,(from-alien-form alien-funcall return-type)
173 ,@(cleanup-forms))
3840beb2 174 ,@(return-values))
310da1d5 175 `(progn
9adccb27 176 (unwind-protect
177 ,alien-funcall
178 ,@(cleanup-forms))
3840beb2 179 (values ,@(return-values)))))))))
310da1d5 180
181
9adccb27 182;;; Creates bindings at runtime
310da1d5 183(defun mkbinding (name return-type &rest arg-types)
73572c12 184 #+cmu(declare (optimize (inhibit-warnings 3)))
185 #+sbcl(declare (muffle-conditions compiler-note))
9adccb27 186 (let* ((ftype
187 `(function ,@(mapcar #'alien-type (cons return-type arg-types))))
310da1d5 188 (alien
73572c12 189 (%heap-alien
190 (make-heap-alien-info
191 :type (parse-alien-type ftype #+sbcl nil)
177abaa0 192 :sap-form (let ((address (foreign-symbol-address name)))
193 (etypecase address
194 (integer (int-sap address))
195 (system-area-pointer address))))))
9adccb27 196 (translate-arguments (mapcar #'to-alien-function arg-types))
197 (translate-return-value (from-alien-function return-type))
198 (cleanup-arguments (mapcar #'cleanup-function arg-types)))
199
310da1d5 200 #'(lambda (&rest args)
201 (map-into args #'funcall translate-arguments args)
202 (prog1
9adccb27 203 (funcall translate-return-value
73572c12 204 (apply #'alien-funcall alien args))
310da1d5 205 (mapc #'funcall cleanup-arguments args)))))
206
8755b1a5 207
73572c12 208
586328b4 209;;;; C callbacks
210
211(defmacro define-callback (name return-type args &body body)
212 (let ((define-callback
213 #+cmu'alien:def-callback
214 #+(and sbcl alien-callbacks)'sb-alien::define-alien-callback
215 #+(and sbcl (not alien-callbacks))'sb-alien:define-alien-function))
216 (multiple-value-bind (doc declaration body)
217 (cond
218 ((and (stringp (first body)) (eq (cadr body) 'declare))
219 (values (first body) (second body) (cddr body)))
220 ((stringp (first body))
221 (values (first body) nil (rest body)))
222 ((eq (caar body) 'declare)
223 (values nil (first body) (rest body)))
224 (t (values nil nil body)))
225 `(,define-callback ,name
226 #+(and sbcl alien-callbacks),(alien-type return-type)
227 (#+(or cmu (and sbcl (not alien-callbacks))),(alien-type return-type)
228 ,@(mapcar #'(lambda (arg)
229 (destructuring-bind (name type) arg
230 `(,name ,(alien-type type))))
231 args))
232 ,@(when doc (list doc))
233 ,(to-alien-form
234 `(let (,@(loop
235 for (name type) in args
236 as from-alien-form = (callback-from-alien-form name type)
237 collect `(,name ,from-alien-form)))
238 ,@(when declaration (list declaration))
239 (unwind-protect
240 (progn ,@body)
241 ,@(loop
242 for (name type) in args
243 do (callback-cleanup-form name type))))
244
245 return-type)))))
246
247(defun callback-address (callback)
248 #+cmu(alien::callback-trampoline callback)
249 #+(and sbcl (not alien-callbacks))(sb-alien:alien-function-sap callback)
250 #+(and sbcl alien-callbacks)(sb-alien:alien-sap callback))
8755b1a5 251
7e29d6b1 252#+sbcl
586328b4 253(deftype callback ()
254 #-alien-callbacks'sb-alien:alien-function
255 #+alien-callbacks'sb-alien:alien)
256
257
258;;; These are for backward compatibility
259
260(defmacro defcallback (name (return-type &rest args) &body body)
261 `(define-callback ,name ,return-type ,args ,@body))
262
263#-cmu
264(defun callback (callback)
265 (callback-address callback))
266
267
310da1d5 268
269;;;; Definitons and translations of fundamental types
270
9adccb27 271(defmacro def-type-method (name args &optional documentation)
272 `(progn
273 (defgeneric ,name (,@args type &rest args)
274 ,@(when documentation `((:documentation ,documentation))))
275 (defmethod ,name (,@args (type symbol) &rest args)
276 (let ((class (find-class type nil)))
277 (if class
278 (apply #',name ,@args class args)
279 (multiple-value-bind (super-type expanded-p)
280 (type-expand-1 (cons type args))
281 (if expanded-p
282 (,name ,@args super-type)
283 (call-next-method))))))
284 (defmethod ,name (,@args (type cons) &rest args)
285 (declare (ignore args))
286 (apply #',name ,@args (first type) (rest type)))))
287
310da1d5 288
9adccb27 289(def-type-method alien-type ())
290(def-type-method size-of ())
291(def-type-method to-alien-form (form))
292(def-type-method from-alien-form (form))
293(def-type-method cleanup-form (form)
294 "Creates a form to clean up after the alien call has finished.")
586328b4 295(def-type-method callback-from-alien-form (form))
296(def-type-method callback-cleanup-form (form))
310da1d5 297
9adccb27 298(def-type-method to-alien-function ())
299(def-type-method from-alien-function ())
300(def-type-method cleanup-function ())
310da1d5 301
9ca5565a 302(def-type-method copy-to-alien-form (form))
303(def-type-method copy-to-alien-function ())
304(def-type-method copy-from-alien-form (form))
305(def-type-method copy-from-alien-function ())
306
9adccb27 307(def-type-method writer-function ())
308(def-type-method reader-function ())
309(def-type-method destroy-function ())
310da1d5 310
12b7df04 311(def-type-method unbound-value ()
312 "First return value is true if the type has an unbound value, second return value is the actual unbound value")
313
310da1d5 314
8755b1a5 315;; Sizes of fundamental C types in bytes (8 bits)
316(defconstant +size-of-short+ 2)
317(defconstant +size-of-int+ 4)
318(defconstant +size-of-long+ 4)
319(defconstant +size-of-pointer+ 4)
320(defconstant +size-of-float+ 4)
321(defconstant +size-of-double+ 8)
322
323;; Sizes of fundamental C types in bits
324(defconstant +bits-of-byte+ 8)
325(defconstant +bits-of-short+ 16)
326(defconstant +bits-of-int+ 32)
327(defconstant +bits-of-long+ 32)
328
329
9adccb27 330(deftype int () '(signed-byte #.+bits-of-int+))
331(deftype unsigned-int () '(unsigned-byte #.+bits-of-int+))
332(deftype long () '(signed-byte #.+bits-of-long+))
333(deftype unsigned-long () '(unsigned-byte #.+bits-of-long+))
334(deftype short () '(signed-byte #.+bits-of-short+))
335(deftype unsigned-short () '(unsigned-byte #.+bits-of-short+))
336(deftype signed (&optional (size '*)) `(signed-byte ,size))
337(deftype unsigned (&optional (size '*)) `(unsigned-byte ,size))
338(deftype char () 'base-char)
339(deftype pointer () 'system-area-pointer)
340(deftype boolean (&optional (size '*)) (declare (ignore size)) `(member t nil))
341;(deftype invalid () nil)
310da1d5 342
343
9adccb27 344(defmethod to-alien-form (form (type t) &rest args)
345 (declare (ignore type args))
346 form)
310da1d5 347
9adccb27 348(defmethod to-alien-function ((type t) &rest args)
349 (declare (ignore type args))
350 #'identity)
310da1d5 351
9adccb27 352(defmethod from-alien-form (form (type t) &rest args)
353 (declare (ignore type args))
354 form)
310da1d5 355
9adccb27 356(defmethod from-alien-function ((type t) &rest args)
357 (declare (ignore type args))
358 #'identity)
359
360(defmethod cleanup-form (form (type t) &rest args)
361 (declare (ignore form type args))
362 nil)
310da1d5 363
9adccb27 364(defmethod cleanup-function ((type t) &rest args)
365 (declare (ignore type args))
366 #'identity)
367
586328b4 368(defmethod callback-from-alien-form (form (type t) &rest args)
369 (apply #'copy-from-alien-form form type args))
370
371(defmethod callback-cleanup-form (form (type t) &rest args)
372 (declare (ignore form type args))
373 nil)
374
9adccb27 375(defmethod destroy-function ((type t) &rest args)
376 (declare (ignore type args))
cdd375f3 377 #'(lambda (location &optional offset)
9adccb27 378 (declare (ignore location offset))))
379
9ca5565a 380(defmethod copy-to-alien-form (form (type t) &rest args)
381 (apply #'to-alien-form form type args))
382
383(defmethod copy-to-alien-function ((type t) &rest args)
384 (apply #'to-alien-function type args))
385
386(defmethod copy-from-alien-form (form (type t) &rest args)
387 (apply #'from-alien-form form type args))
388
389(defmethod copy-from-alien-function ((type t) &rest args)
390 (apply #'from-alien-function type args))
391
9adccb27 392(defmethod alien-type ((type (eql 'signed-byte)) &rest args)
393 (declare (ignore type))
394 (destructuring-bind (&optional (size '*)) args
395 (ecase size
73572c12 396 (#.+bits-of-byte+ #+cmu'(alien:signed 8) #+sbcl'(sb-alien:signed 8))
397 (#.+bits-of-short+ #+cmu 'c-call:short #+sbcl 'sb-alien:short)
398 ((* #.+bits-of-int+) #+cmu 'c-call:int #+sbcl 'sb-alien:int)
399 (#.+bits-of-long+ #+cmu 'c-call:long #+sbcl 'sb-alien:long))))
9adccb27 400
401(defmethod size-of ((type (eql 'signed-byte)) &rest args)
402 (declare (ignore type))
403 (destructuring-bind (&optional (size '*)) args
404 (ecase size
405 (#.+bits-of-byte+ 1)
406 (#.+bits-of-short+ +size-of-short+)
407 ((* #.+bits-of-int+) +size-of-int+)
408 (#.+bits-of-long+ +size-of-long+))))
409
12b7df04 410(defmethod unbound-value ((type t) &rest args)
411 (declare (ignore type args))
412 nil)
413
9adccb27 414(defmethod writer-function ((type (eql 'signed-byte)) &rest args)
415 (declare (ignore type))
416 (destructuring-bind (&optional (size '*)) args
417 (let ((size (if (eq size '*) +bits-of-int+ size)))
418 (ecase size
419 (8 #'(lambda (value location &optional (offset 0))
420 (setf (signed-sap-ref-8 location offset) value)))
421 (16 #'(lambda (value location &optional (offset 0))
422 (setf (signed-sap-ref-16 location offset) value)))
423 (32 #'(lambda (value location &optional (offset 0))
424 (setf (signed-sap-ref-32 location offset) value)))
425 (64 #'(lambda (value location &optional (offset 0))
426 (setf (signed-sap-ref-64 location offset) value)))))))
427
428(defmethod reader-function ((type (eql 'signed-byte)) &rest args)
429 (declare (ignore type))
430 (destructuring-bind (&optional (size '*)) args
431 (let ((size (if (eq size '*) +bits-of-int+ size)))
432 (ecase size
3005806e 433 (8 #'(lambda (sap &optional (offset 0) weak-p)
434 (declare (ignore weak-p))
9adccb27 435 (signed-sap-ref-8 sap offset)))
3005806e 436 (16 #'(lambda (sap &optional (offset 0) weak-p)
437 (declare (ignore weak-p))
9adccb27 438 (signed-sap-ref-16 sap offset)))
3005806e 439 (32 #'(lambda (sap &optional (offset 0) weak-p)
440 (declare (ignore weak-p))
9adccb27 441 (signed-sap-ref-32 sap offset)))
3005806e 442 (64 #'(lambda (sap &optional (offset 0) weak-p)
443 (declare (ignore weak-p))
9adccb27 444 (signed-sap-ref-64 sap offset)))))))
445
446(defmethod alien-type ((type (eql 'unsigned-byte)) &rest args)
447 (destructuring-bind (&optional (size '*)) args
448 (ecase size
73572c12 449 (#.+bits-of-byte+ #+cmu'(alien:unsigned 8) #+sbcl'(sb-alien:unsigned 8))
450 (#.+bits-of-short+ #+cmu 'c-call:unsigned-short
451 #+sbcl 'sb-alien:unsigned-short)
452 ((* #.+bits-of-int+) #+cmu 'c-call:unsigned-int
453 #+sbcl 'sb-alien:unsigned-int)
454 (#.+bits-of-long+ #+cmu 'c-call:unsigned-long
455 #+sbcl 'sb-alien:unsigned-long))))
9adccb27 456
457(defmethod size-of ((type (eql 'unsigned-byte)) &rest args)
458 (apply #'size-of 'signed args))
459
460(defmethod writer-function ((type (eql 'unsigned-byte)) &rest args)
461 (declare (ignore type))
462 (destructuring-bind (&optional (size '*)) args
463 (let ((size (if (eq size '*) +bits-of-int+ size)))
464 (ecase size
465 (8 #'(lambda (value location &optional (offset 0))
466 (setf (sap-ref-8 location offset) value)))
467 (16 #'(lambda (value location &optional (offset 0))
468 (setf (sap-ref-16 location offset) value)))
469 (32 #'(lambda (value location &optional (offset 0))
470 (setf (sap-ref-32 location offset) value)))
471 (64 #'(lambda (value location &optional (offset 0))
472 (setf (sap-ref-64 location offset) value)))))))
473
474(defmethod reader-function ((type (eql 'unsigned-byte)) &rest args)
475 (declare (ignore type))
476 (destructuring-bind (&optional (size '*)) args
477 (let ((size (if (eq size '*) +bits-of-int+ size)))
478 (ecase size
3005806e 479 (8 #'(lambda (sap &optional (offset 0) weak-p)
480 (declare (ignore weak-p))
9adccb27 481 (sap-ref-8 sap offset)))
3005806e 482 (16 #'(lambda (sap &optional (offset 0) weak-p)
483 (declare (ignore weak-p))
9adccb27 484 (sap-ref-16 sap offset)))
3005806e 485 (32 #'(lambda (sap &optional (offset 0) weak-p)
486 (declare (ignore weak-p))
9adccb27 487 (sap-ref-32 sap offset)))
3005806e 488 (64 #'(lambda (sap &optional (offset 0) weak-p)
489 (declare (ignore weak-p))
9adccb27 490 (sap-ref-64 sap offset)))))))
491
492
493(defmethod alien-type ((type (eql 'integer)) &rest args)
494 (declare (ignore type args))
495 (alien-type 'signed-byte))
310da1d5 496
9adccb27 497(defmethod size-of ((type (eql 'integer)) &rest args)
498 (declare (ignore type args))
499 (size-of 'signed-byte))
310da1d5 500
78778e5a 501(defmethod writer-function ((type (eql 'integer)) &rest args)
502 (declare (ignore type args))
503 (writer-function 'signed-byte))
504
505(defmethod reader-function ((type (eql 'integer)) &rest args)
506 (declare (ignore type args))
507 (reader-function 'signed-byte))
508
310da1d5 509
9adccb27 510(defmethod alien-type ((type (eql 'fixnum)) &rest args)
511 (declare (ignore type args))
512 (alien-type 'signed-byte))
310da1d5 513
9adccb27 514(defmethod size-of ((type (eql 'fixnum)) &rest args)
515 (declare (ignore type args))
516 (size-of 'signed-byte))
310da1d5 517
518
9adccb27 519(defmethod alien-type ((type (eql 'single-float)) &rest args)
520 (declare (ignore type args))
73572c12 521 #+cmu 'alien:single-float #+sbcl 'sb-alien:single-float)
310da1d5 522
9adccb27 523(defmethod size-of ((type (eql 'single-float)) &rest args)
524 (declare (ignore type args))
310da1d5 525 +size-of-float+)
526
af6d8c9a 527(defmethod to-alien-form (form (type (eql 'single-float)) &rest args)
528 (declare (ignore type args))
529 `(coerce ,form 'single-float))
530
531(defmethod to-alien-function ((type (eql 'single-float)) &rest args)
532 (declare (ignore type args))
533 #'(lambda (number)
534 (coerce number 'single-float)))
535
9adccb27 536(defmethod writer-function ((type (eql 'single-float)) &rest args)
537 (declare (ignore type args))
538 #'(lambda (value location &optional (offset 0))
8755b1a5 539 (setf (sap-ref-single location offset) (coerce value 'single-float))))
310da1d5 540
9adccb27 541(defmethod reader-function ((type (eql 'single-float)) &rest args)
542 (declare (ignore type args))
3005806e 543 #'(lambda (sap &optional (offset 0) weak-p)
544 (declare (ignore weak-p))
9adccb27 545 (sap-ref-single sap offset)))
310da1d5 546
547
9adccb27 548(defmethod alien-type ((type (eql 'double-float)) &rest args)
549 (declare (ignore type args))
73572c12 550 #+cmu 'alien:double-float #+sbcl 'sb-alien:double-float)
310da1d5 551
9adccb27 552(defmethod size-of ((type (eql 'double-float)) &rest args)
553 (declare (ignore type args))
3d285e35 554 +size-of-double+)
310da1d5 555
af6d8c9a 556(defmethod to-alien-form (form (type (eql 'double-float)) &rest args)
557 (declare (ignore type args))
558 `(coerce ,form 'double-float))
559
560(defmethod to-alien-function ((type (eql 'double-float)) &rest args)
561 (declare (ignore type args))
562 #'(lambda (number)
563 (coerce number 'double-float)))
564
9adccb27 565(defmethod writer-function ((type (eql 'double-float)) &rest args)
566 (declare (ignore type args))
567 #'(lambda (value location &optional (offset 0))
568 (setf (sap-ref-double location offset) (coerce value 'double-float))))
310da1d5 569
9adccb27 570(defmethod reader-function ((type (eql 'double-float)) &rest args)
571 (declare (ignore type args))
3005806e 572 #'(lambda (sap &optional (offset 0) weak-p)
573 (declare (ignore weak-p))
9adccb27 574 (sap-ref-double sap offset)))
310da1d5 575
576
9adccb27 577(defmethod alien-type ((type (eql 'base-char)) &rest args)
578 (declare (ignore type args))
73572c12 579 #+cmu 'c-call:char #+sbcl 'sb-alien:char)
310da1d5 580
9adccb27 581(defmethod size-of ((type (eql 'base-char)) &rest args)
582 (declare (ignore type args))
310da1d5 583 1)
584
9adccb27 585(defmethod writer-function ((type (eql 'base-char)) &rest args)
586 (declare (ignore type args))
587 #'(lambda (char location &optional (offset 0))
588 (setf (sap-ref-8 location offset) (char-code char))))
310da1d5 589
9adccb27 590(defmethod reader-function ((type (eql 'base-char)) &rest args)
591 (declare (ignore type args))
3005806e 592 #'(lambda (location &optional (offset 0) weak-p)
593 (declare (ignore weak-p))
9adccb27 594 (code-char (sap-ref-8 location offset))))
310da1d5 595
596
9adccb27 597(defmethod alien-type ((type (eql 'string)) &rest args)
598 (declare (ignore type args))
599 (alien-type 'pointer))
310da1d5 600
9adccb27 601(defmethod size-of ((type (eql 'string)) &rest args)
602 (declare (ignore type args))
603 (size-of 'pointer))
310da1d5 604
9adccb27 605(defmethod to-alien-form (string (type (eql 'string)) &rest args)
606 (declare (ignore type args))
310da1d5 607 `(let ((string ,string))
608 ;; Always copy strings to prevent seg fault due to GC
6896c0f3 609 #+cmu
310da1d5 610 (copy-memory
73572c12 611 (vector-sap (coerce string 'simple-base-string))
6896c0f3 612 (1+ (length string)))
613 #+sbcl
614 (let ((utf8 (%deport-utf8-string string)))
615 (copy-memory (vector-sap utf8) (length utf8)))))
310da1d5 616
9adccb27 617(defmethod to-alien-function ((type (eql 'string)) &rest args)
618 (declare (ignore type args))
619 #'(lambda (string)
6896c0f3 620 #+cmu
9adccb27 621 (copy-memory
73572c12 622 (vector-sap (coerce string 'simple-base-string))
6896c0f3 623 (1+ (length string)))
624 #+sbcl
625 (let ((utf8 (%deport-utf8-string string)))
626 (copy-memory (vector-sap utf8) (length utf8)))))
9adccb27 627
628(defmethod from-alien-form (string (type (eql 'string)) &rest args)
629 (declare (ignore type args))
630 `(let ((string ,string))
631 (unless (null-pointer-p string)
9ca5565a 632 (prog1
6896c0f3 633 #+cmu(%naturalize-c-string string)
634 #+sbcl(%naturalize-utf8-string string)
9ca5565a 635 (deallocate-memory string)))))
310da1d5 636
9adccb27 637(defmethod from-alien-function ((type (eql 'string)) &rest args)
638 (declare (ignore type args))
639 #'(lambda (string)
640 (unless (null-pointer-p string)
9ca5565a 641 (prog1
6896c0f3 642 #+cmu(%naturalize-c-string string)
643 #+sbcl(%naturalize-utf8-string string)
9ca5565a 644 (deallocate-memory string)))))
310da1d5 645
9adccb27 646(defmethod cleanup-form (string (type (eql 'string)) &rest args)
647 (declare (ignore type args))
648 `(let ((string ,string))
649 (unless (null-pointer-p string)
650 (deallocate-memory string))))
651
652(defmethod cleanup-function ((type (eql 'string)) &rest args)
8755b1a5 653 (declare (ignore args))
9adccb27 654 #'(lambda (string)
655 (unless (null-pointer-p string)
656 (deallocate-memory string))))
657
9ca5565a 658(defmethod copy-from-alien-form (string (type (eql 'string)) &rest args)
659 (declare (ignore type args))
660 `(let ((string ,string))
661 (unless (null-pointer-p string)
6896c0f3 662 #+cmu(%naturalize-c-string string)
663 #+sbcl(%naturalize-utf8-string string))))
9ca5565a 664
665(defmethod copy-from-alien-function ((type (eql 'string)) &rest args)
666 (declare (ignore type args))
667 #'(lambda (string)
668 (unless (null-pointer-p string)
6896c0f3 669 #+cmu(%naturalize-c-string string)
670 #+sbcl(%naturalize-utf8-string string))))
9ca5565a 671
9adccb27 672(defmethod writer-function ((type (eql 'string)) &rest args)
673 (declare (ignore type args))
674 #'(lambda (string location &optional (offset 0))
675 (assert (null-pointer-p (sap-ref-sap location offset)))
676 (setf (sap-ref-sap location offset)
6896c0f3 677 #+cmu
9adccb27 678 (copy-memory
73572c12 679 (vector-sap (coerce string 'simple-base-string))
6896c0f3 680 (1+ (length string)))
681 #+sbcl
682 (let ((utf8 (%deport-utf8-string string)))
683 (copy-memory (vector-sap utf8) (length utf8))))))
9adccb27 684
685(defmethod reader-function ((type (eql 'string)) &rest args)
686 (declare (ignore type args))
3005806e 687 #'(lambda (location &optional (offset 0) weak-p)
688 (declare (ignore weak-p))
9adccb27 689 (unless (null-pointer-p (sap-ref-sap location offset))
6896c0f3 690 #+cmu(%naturalize-c-string (sap-ref-sap location offset))
691 #+sbcl(%naturalize-utf8-string (sap-ref-sap location offset)))))
9adccb27 692
693(defmethod destroy-function ((type (eql 'string)) &rest args)
694 (declare (ignore type args))
695 #'(lambda (location &optional (offset 0))
696 (unless (null-pointer-p (sap-ref-sap location offset))
697 (deallocate-memory (sap-ref-sap location offset))
698 (setf (sap-ref-sap location offset) (make-pointer 0)))))
699
12b7df04 700(defmethod unbound-value ((type (eql 'string)) &rest args)
701 (declare (ignore type args))
702 (values t nil))
9adccb27 703
6896c0f3 704
9adccb27 705(defmethod alien-type ((type (eql 'pathname)) &rest args)
706 (declare (ignore type args))
707 (alien-type 'string))
708
709(defmethod size-of ((type (eql 'pathname)) &rest args)
710 (declare (ignore type args))
711 (size-of 'string))
310da1d5 712
9adccb27 713(defmethod to-alien-form (path (type (eql 'pathname)) &rest args)
714 (declare (ignore type args))
715 (to-alien-form `(namestring (translate-logical-pathname ,path)) 'string))
716
717(defmethod to-alien-function ((type (eql 'pathname)) &rest args)
718 (declare (ignore type args))
719 (let ((string-function (to-alien-function 'string)))
720 #'(lambda (path)
721 (funcall string-function (namestring path)))))
722
723(defmethod from-alien-form (string (type (eql 'pathname)) &rest args)
724 (declare (ignore type args))
725 `(parse-namestring ,(from-alien-form string 'string)))
726
727(defmethod from-alien-function ((type (eql 'pathname)) &rest args)
728 (declare (ignore type args))
729 (let ((string-function (from-alien-function 'string)))
730 #'(lambda (string)
731 (parse-namestring (funcall string-function string)))))
732
733(defmethod cleanup-form (string (type (eql 'pathnanme)) &rest args)
734 (declare (ignore type args))
735 (cleanup-form string 'string))
736
737(defmethod cleanup-function ((type (eql 'pathnanme)) &rest args)
738 (declare (ignore type args))
739 (cleanup-function 'string))
740
741(defmethod writer-function ((type (eql 'pathname)) &rest args)
742 (declare (ignore type args))
743 (let ((string-writer (writer-function 'string)))
744 #'(lambda (path location &optional (offset 0))
745 (funcall string-writer (namestring path) location offset))))
746
747(defmethod reader-function ((type (eql 'pathname)) &rest args)
748 (declare (ignore type args))
749 (let ((string-reader (reader-function 'string)))
3005806e 750 #'(lambda (location &optional (offset 0) weak-p)
751 (declare (ignore weak-p))
9adccb27 752 (let ((string (funcall string-reader location offset)))
753 (when string
754 (parse-namestring string))))))
755
756(defmethod destroy-function ((type (eql 'pathname)) &rest args)
757 (declare (ignore type args))
758 (destroy-function 'string))
759
12b7df04 760(defmethod unbound-value ((type (eql 'pathname)) &rest args)
761 (declare (ignore type args))
762 (unbound-value 'string))
763
9adccb27 764
765(defmethod alien-type ((type (eql 'boolean)) &rest args)
766 (apply #'alien-type 'signed-byte args))
767
768(defmethod size-of ((type (eql 'boolean)) &rest args)
769 (apply #'size-of 'signed-byte args))
770
771(defmethod to-alien-form (boolean (type (eql 'boolean)) &rest args)
772 (declare (ignore type args))
310da1d5 773 `(if ,boolean 1 0))
774
9adccb27 775(defmethod to-alien-function ((type (eql 'boolean)) &rest args)
776 (declare (ignore type args))
777 #'(lambda (boolean)
778 (if boolean 1 0)))
779
780(defmethod from-alien-form (boolean (type (eql 'boolean)) &rest args)
781 (declare (ignore type args))
782 `(not (zerop ,boolean)))
783
784(defmethod from-alien-function ((type (eql 'boolean)) &rest args)
785 (declare (ignore type args))
786 #'(lambda (boolean)
787 (not (zerop boolean))))
788
789(defmethod writer-function ((type (eql 'boolean)) &rest args)
790 (declare (ignore type))
791 (let ((writer (apply #'writer-function 'signed-byte args)))
792 #'(lambda (boolean location &optional (offset 0))
793 (funcall writer (if boolean 1 0) location offset))))
794
795(defmethod reader-function ((type (eql 'boolean)) &rest args)
796 (declare (ignore type))
797 (let ((reader (apply #'reader-function 'signed-byte args)))
3005806e 798 #'(lambda (location &optional (offset 0) weak-p)
799 (declare (ignore weak-p))
9adccb27 800 (not (zerop (funcall reader location offset))))))
801
802
803(defmethod alien-type ((type (eql 'or)) &rest args)
804 (let ((alien-type (alien-type (first args))))
805 (unless (every #'(lambda (type)
806 (eq alien-type (alien-type type)))
807 (rest args))
808 (error "No common alien type specifier for union type: ~A"
809 (cons type args)))
310da1d5 810 alien-type))
811
9adccb27 812(defmethod size-of ((type (eql 'or)) &rest args)
813 (declare (ignore type))
814 (size-of (first args)))
815
816(defmethod to-alien-form (form (type (eql 'or)) &rest args)
817 (declare (ignore type))
818 `(let ((value ,form))
819 (etypecase value
820 ,@(mapcar
821 #'(lambda (type)
822 `(,type ,(to-alien-form 'value type)))
823 args))))
824
825(defmethod to-alien-function ((type (eql 'or)) &rest types)
826 (declare (ignore type))
827 (let ((functions (mapcar #'to-alien-function types)))
828 #'(lambda (value)
829 (loop
830 for function in functions
831 for type in types
832 when (typep value type)
833 do (return (funcall function value))
834 finally (error "~S is not of type ~A" value `(or ,@types))))))
835
836(defmethod alien-type ((type (eql 'system-area-pointer)) &rest args)
837 (declare (ignore type args))
310da1d5 838 'system-area-pointer)
839
9adccb27 840(defmethod size-of ((type (eql 'system-area-pointer)) &rest args)
841 (declare (ignore type args))
842 +size-of-pointer+)
310da1d5 843
9adccb27 844(defmethod writer-function ((type (eql 'system-area-pointer)) &rest args)
845 (declare (ignore type args))
846 #'(lambda (sap location &optional (offset 0))
847 (setf (sap-ref-sap location offset) sap)))
310da1d5 848
9adccb27 849(defmethod reader-function ((type (eql 'system-area-pointer)) &rest args)
850 (declare (ignore type args))
3005806e 851 #'(lambda (location &optional (offset 0) weak-p)
852 (declare (ignore weak-p))
9adccb27 853 (sap-ref-sap location offset)))
310da1d5 854
855
9adccb27 856(defmethod alien-type ((type (eql 'null)) &rest args)
857 (declare (ignore type args))
858 (alien-type 'pointer))
310da1d5 859
9adccb27 860(defmethod size-of ((type (eql 'null)) &rest args)
861 (declare (ignore type args))
862 (size-of 'pointer))
863
864(defmethod to-alien-form (null (type (eql 'null)) &rest args)
865 (declare (ignore null type args))
310da1d5 866 `(make-pointer 0))
867
9adccb27 868(defmethod to-alien-function ((type (eql 'null)) &rest args)
869 (declare (ignore type args))
870 #'(lambda (null)
871 (declare (ignore null))
872 (make-pointer 0)))
310da1d5 873
310da1d5 874
9adccb27 875(defmethod alien-type ((type (eql 'nil)) &rest args)
876 (declare (ignore type args))
73572c12 877 'void)
9adccb27 878
879(defmethod from-alien-function ((type (eql 'nil)) &rest args)
880 (declare (ignore type args))
881 #'(lambda (value)
882 (declare (ignore value))
883 (values)))
9ca5565a 884
885
886(defmethod alien-type ((type (eql 'copy-of)) &rest args)
887 (declare (ignore type))
888 (alien-type (first args)))
889
890(defmethod size-of ((type (eql 'copy-of)) &rest args)
891 (declare (ignore type))
892 (size-of (first args)))
893
894(defmethod to-alien-form (form (type (eql 'copy-of)) &rest args)
895 (declare (ignore type))
896 (copy-to-alien-form form (first args)))
897
898(defmethod to-alien-function ((type (eql 'copy-of)) &rest args)
899 (declare (ignore type))
900 (copy-to-alien-function (first args)))
901
902(defmethod from-alien-form (form (type (eql 'copy-of)) &rest args)
903 (declare (ignore type))
904 (copy-from-alien-form form (first args)))
905
906(defmethod from-alien-function ((type (eql 'copy-of)) &rest args)
907 (declare (ignore type))
908 (copy-from-alien-function (first args)))
909
cdd375f3 910(defmethod reader-function ((type (eql 'copy-of)) &rest args)
911 (declare (ignore type))
912 (reader-function (first args)))
913
914(defmethod writer-function ((type (eql 'copy-of)) &rest args)
915 (declare (ignore type))
916 (writer-function (first args)))
46759268 917
918
919(defmethod alien-type ((type (eql 'callback)) &rest args)
920 (declare (ignore type args))
921 (alien-type 'pointer))
922
586328b4 923#+nil
46759268 924(defmethod size-of ((type (eql 'callback)) &rest args)
925 (declare (ignore type args))
926 (size-of 'pointer))
927
928(defmethod to-alien-form (callback (type (eql 'callback)) &rest args)
929 (declare (ignore type args))
586328b4 930 `(callback-address ,callback))
46759268 931
932(defmethod to-alien-function ((type (eql 'callback)) &rest args)
933 (declare (ignore type args))
586328b4 934 #'callback-address)
46759268 935
586328b4 936#+nil(
46759268 937#+cmu
938(defun find-callback (pointer)
939 (find pointer alien::*callbacks* :key #'callback-trampoline :test #'sap=))
940
941(defmethod from-alien-form (pointer (type (eql 'callback)) &rest args)
942 (declare (ignore type args))
943 #+cmu `(find-callback ,pointer)
944 #+sbcl `(sb-alien::%find-alien-function ,pointer))
945
946(defmethod from-alien-function ((type (eql 'callback)) &rest args)
947 (declare (ignore type args))
948 #+cmu #'find-callback
949 #+sbcl #'sb-alien::%find-alien-function)
950
951(defmethod writer-function ((type (eql 'callback)) &rest args)
952 (declare (ignore type args))
953 (let ((writer (writer-function 'pointer))
954 (to-alien (to-alien-function 'callback)))
955 #'(lambda (callback location &optional (offset 0))
956 (funcall writer (funcall to-alien callback) location offset))))
957
958(defmethod reader-function ((type (eql 'callback)) &rest args)
959 (declare (ignore type args))
960 (let ((reader (reader-function 'pointer))
961 (from-alien (from-alien-function 'callback)))
3005806e 962 #'(lambda (location &optional (offset 0) weak-p)
963 (declare (ignore weak-p))
46759268 964 (let ((pointer (funcall reader location offset)))
965 (unless (null-pointer-p pointer)
966 (funcall from-alien pointer))))))
967
968(defmethod unbound-value ((type (eql 'callback)) &rest args)
969 (declare (ignore type args))
970 (values t nil))
586328b4 971)