chiark / gitweb /
Build instructions updated for SBCL with native C callback support
[clg] / glib / ffi.lisp
CommitLineData
55212af1 1;; Common Lisp bindings for GTK+ v2.x
2;; Copyright 1999-2005 Espen S. Johnsen <espen@users.sf.net>
fc358945 3;;
55212af1 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:
fc358945 11;;
55212af1 12;; The above copyright notice and this permission notice shall be
13;; included in all copies or substantial portions of the Software.
fc358945 14;;
55212af1 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
ae17423c 23;; $Id: ffi.lisp,v 1.24 2006/02/19 19:17:45 espen Exp $
fc358945 24
25(in-package "GLIB")
26
fc358945 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)
58ddfaac 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*)))
fc358945 68 (if (or (not prefix) (string= prefix ""))
58ddfaac 69 stripped-name
70 (format nil "~A_~A" prefix stripped-name))))
fc358945 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
6baf860c 91(defmacro defbinding (name lambda-list return-type &rest docs/args)
fc358945 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
6cb19a68 105 (unless (member style '(:in :out :in-out :return))
fc358945 106 (error "Bogus argument style ~S in ~S." style doc/arg))
107 (when (and
108 (not supplied-lambda-list)
6cb19a68 109 (namep expr) (member style '(:in :in-out :return)))
fc358945 110 (push expr lambda-list))
e37c4285 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)))))
fc358945 116
117 (%defbinding
118 c-name lisp-name (or supplied-lambda-list (nreverse lambda-list))
6baf860c 119 return-type (reverse docs) (reverse args)))))
fc358945 120
3d36c5d6 121#+(or cmu sbcl)
6baf860c 122(defun %defbinding (foreign-name lisp-name lambda-list return-type docs args)
3d36c5d6 123 (collect ((alien-types) (alien-bindings) (alien-parameters)
124 (return-values) (cleanup-forms))
fc358945 125 (dolist (arg args)
6baf860c 126 (destructuring-bind (var expr type style) arg
127 (let ((declaration (alien-type type))
128 (cleanup (cleanup-form var type)))
129
fc358945 130 (cond
6cb19a68 131 ((member style '(:out :in-out))
132 (alien-types `(* ,declaration))
133 (alien-parameters `(addr ,var))
134 (alien-bindings
135 `(,var ,declaration
4eac8484 136 ,@(cond
137 ((eq style :in-out) (list (to-alien-form expr type)))
138 ((eq declaration 'system-area-pointer)
139 (list '(make-pointer 0))))))
6cb19a68 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)))))))
fc358945 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
3d36c5d6 161 #+cmu(declare (optimize (inhibit-warnings 3)))
162 #+sbcl(declare (muffle-conditions compiler-note))
fc358945 163 (with-alien ((,alien-name
164 (function
6baf860c 165 ,(alien-type return-type)
fc358945 166 ,@(alien-types))
167 :extern ,foreign-name)
168 ,@(alien-bindings))
6baf860c 169 ,(if return-type
170 `(values
171 (unwind-protect
172 ,(from-alien-form alien-funcall return-type)
173 ,@(cleanup-forms))
6cb19a68 174 ,@(return-values))
fc358945 175 `(progn
6baf860c 176 (unwind-protect
177 ,alien-funcall
178 ,@(cleanup-forms))
6cb19a68 179 (values ,@(return-values)))))))))
fc358945 180
181
6baf860c 182;;; Creates bindings at runtime
fc358945 183(defun mkbinding (name return-type &rest arg-types)
3d36c5d6 184 #+cmu(declare (optimize (inhibit-warnings 3)))
185 #+sbcl(declare (muffle-conditions compiler-note))
6baf860c 186 (let* ((ftype
187 `(function ,@(mapcar #'alien-type (cons return-type arg-types))))
fc358945 188 (alien
3d36c5d6 189 (%heap-alien
190 (make-heap-alien-info
191 :type (parse-alien-type ftype #+sbcl nil)
a9392506 192 :sap-form (let ((address (foreign-symbol-address name)))
193 (etypecase address
194 (integer (int-sap address))
195 (system-area-pointer address))))))
6baf860c 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
fc358945 200 #'(lambda (&rest args)
201 (map-into args #'funcall translate-arguments args)
202 (prog1
6baf860c 203 (funcall translate-return-value
3d36c5d6 204 (apply #'alien-funcall alien args))
fc358945 205 (mapc #'funcall cleanup-arguments args)))))
206
7bde5a67 207
3d36c5d6 208
ae17423c 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))
7bde5a67 251
7aa45361 252#+sbcl
ae17423c 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
fc358945 268
269;;;; Definitons and translations of fundamental types
270
6baf860c 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
fc358945 288
6baf860c 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.")
ae17423c 295(def-type-method callback-from-alien-form (form))
296(def-type-method callback-cleanup-form (form))
fc358945 297
6baf860c 298(def-type-method to-alien-function ())
299(def-type-method from-alien-function ())
300(def-type-method cleanup-function ())
fc358945 301
508d13a7 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
6baf860c 307(def-type-method writer-function ())
308(def-type-method reader-function ())
309(def-type-method destroy-function ())
fc358945 310
b6bf802c 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
fc358945 314
7bde5a67 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
6baf860c 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)
fc358945 342
343
6baf860c 344(defmethod to-alien-form (form (type t) &rest args)
345 (declare (ignore type args))
346 form)
fc358945 347
6baf860c 348(defmethod to-alien-function ((type t) &rest args)
349 (declare (ignore type args))
350 #'identity)
fc358945 351
6baf860c 352(defmethod from-alien-form (form (type t) &rest args)
353 (declare (ignore type args))
354 form)
fc358945 355
6baf860c 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)
fc358945 363
6baf860c 364(defmethod cleanup-function ((type t) &rest args)
365 (declare (ignore type args))
366 #'identity)
367
ae17423c 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
6baf860c 375(defmethod destroy-function ((type t) &rest args)
376 (declare (ignore type args))
4c795125 377 #'(lambda (location &optional offset)
6baf860c 378 (declare (ignore location offset))))
379
508d13a7 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
6baf860c 392(defmethod alien-type ((type (eql 'signed-byte)) &rest args)
393 (declare (ignore type))
394 (destructuring-bind (&optional (size '*)) args
395 (ecase size
3d36c5d6 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))))
6baf860c 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
b6bf802c 410(defmethod unbound-value ((type t) &rest args)
411 (declare (ignore type args))
412 nil)
413
6baf860c 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
0739b019 433 (8 #'(lambda (sap &optional (offset 0) weak-p)
434 (declare (ignore weak-p))
6baf860c 435 (signed-sap-ref-8 sap offset)))
0739b019 436 (16 #'(lambda (sap &optional (offset 0) weak-p)
437 (declare (ignore weak-p))
6baf860c 438 (signed-sap-ref-16 sap offset)))
0739b019 439 (32 #'(lambda (sap &optional (offset 0) weak-p)
440 (declare (ignore weak-p))
6baf860c 441 (signed-sap-ref-32 sap offset)))
0739b019 442 (64 #'(lambda (sap &optional (offset 0) weak-p)
443 (declare (ignore weak-p))
6baf860c 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
3d36c5d6 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))))
6baf860c 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
0739b019 479 (8 #'(lambda (sap &optional (offset 0) weak-p)
480 (declare (ignore weak-p))
6baf860c 481 (sap-ref-8 sap offset)))
0739b019 482 (16 #'(lambda (sap &optional (offset 0) weak-p)
483 (declare (ignore weak-p))
6baf860c 484 (sap-ref-16 sap offset)))
0739b019 485 (32 #'(lambda (sap &optional (offset 0) weak-p)
486 (declare (ignore weak-p))
6baf860c 487 (sap-ref-32 sap offset)))
0739b019 488 (64 #'(lambda (sap &optional (offset 0) weak-p)
489 (declare (ignore weak-p))
6baf860c 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))
fc358945 496
6baf860c 497(defmethod size-of ((type (eql 'integer)) &rest args)
498 (declare (ignore type args))
499 (size-of 'signed-byte))
fc358945 500
42c6b247 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
fc358945 509
6baf860c 510(defmethod alien-type ((type (eql 'fixnum)) &rest args)
511 (declare (ignore type args))
512 (alien-type 'signed-byte))
fc358945 513
6baf860c 514(defmethod size-of ((type (eql 'fixnum)) &rest args)
515 (declare (ignore type args))
516 (size-of 'signed-byte))
fc358945 517
518
6baf860c 519(defmethod alien-type ((type (eql 'single-float)) &rest args)
520 (declare (ignore type args))
3d36c5d6 521 #+cmu 'alien:single-float #+sbcl 'sb-alien:single-float)
fc358945 522
6baf860c 523(defmethod size-of ((type (eql 'single-float)) &rest args)
524 (declare (ignore type args))
fc358945 525 +size-of-float+)
526
472e1aae 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
6baf860c 536(defmethod writer-function ((type (eql 'single-float)) &rest args)
537 (declare (ignore type args))
538 #'(lambda (value location &optional (offset 0))
7bde5a67 539 (setf (sap-ref-single location offset) (coerce value 'single-float))))
fc358945 540
6baf860c 541(defmethod reader-function ((type (eql 'single-float)) &rest args)
542 (declare (ignore type args))
0739b019 543 #'(lambda (sap &optional (offset 0) weak-p)
544 (declare (ignore weak-p))
6baf860c 545 (sap-ref-single sap offset)))
fc358945 546
547
6baf860c 548(defmethod alien-type ((type (eql 'double-float)) &rest args)
549 (declare (ignore type args))
3d36c5d6 550 #+cmu 'alien:double-float #+sbcl 'sb-alien:double-float)
fc358945 551
6baf860c 552(defmethod size-of ((type (eql 'double-float)) &rest args)
553 (declare (ignore type args))
5b50f177 554 +size-of-double+)
fc358945 555
472e1aae 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
6baf860c 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))))
fc358945 569
6baf860c 570(defmethod reader-function ((type (eql 'double-float)) &rest args)
571 (declare (ignore type args))
0739b019 572 #'(lambda (sap &optional (offset 0) weak-p)
573 (declare (ignore weak-p))
6baf860c 574 (sap-ref-double sap offset)))
fc358945 575
576
6baf860c 577(defmethod alien-type ((type (eql 'base-char)) &rest args)
578 (declare (ignore type args))
3d36c5d6 579 #+cmu 'c-call:char #+sbcl 'sb-alien:char)
fc358945 580
6baf860c 581(defmethod size-of ((type (eql 'base-char)) &rest args)
582 (declare (ignore type args))
fc358945 583 1)
584
6baf860c 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))))
fc358945 589
6baf860c 590(defmethod reader-function ((type (eql 'base-char)) &rest args)
591 (declare (ignore type args))
0739b019 592 #'(lambda (location &optional (offset 0) weak-p)
593 (declare (ignore weak-p))
6baf860c 594 (code-char (sap-ref-8 location offset))))
fc358945 595
596
6baf860c 597(defmethod alien-type ((type (eql 'string)) &rest args)
598 (declare (ignore type args))
599 (alien-type 'pointer))
fc358945 600
6baf860c 601(defmethod size-of ((type (eql 'string)) &rest args)
602 (declare (ignore type args))
603 (size-of 'pointer))
fc358945 604
6baf860c 605(defmethod to-alien-form (string (type (eql 'string)) &rest args)
606 (declare (ignore type args))
fc358945 607 `(let ((string ,string))
608 ;; Always copy strings to prevent seg fault due to GC
a9bb8f02 609 #+cmu
fc358945 610 (copy-memory
3d36c5d6 611 (vector-sap (coerce string 'simple-base-string))
a9bb8f02 612 (1+ (length string)))
613 #+sbcl
614 (let ((utf8 (%deport-utf8-string string)))
615 (copy-memory (vector-sap utf8) (length utf8)))))
fc358945 616
6baf860c 617(defmethod to-alien-function ((type (eql 'string)) &rest args)
618 (declare (ignore type args))
619 #'(lambda (string)
a9bb8f02 620 #+cmu
6baf860c 621 (copy-memory
3d36c5d6 622 (vector-sap (coerce string 'simple-base-string))
a9bb8f02 623 (1+ (length string)))
624 #+sbcl
625 (let ((utf8 (%deport-utf8-string string)))
626 (copy-memory (vector-sap utf8) (length utf8)))))
6baf860c 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)
508d13a7 632 (prog1
a9bb8f02 633 #+cmu(%naturalize-c-string string)
634 #+sbcl(%naturalize-utf8-string string)
508d13a7 635 (deallocate-memory string)))))
fc358945 636
6baf860c 637(defmethod from-alien-function ((type (eql 'string)) &rest args)
638 (declare (ignore type args))
639 #'(lambda (string)
640 (unless (null-pointer-p string)
508d13a7 641 (prog1
a9bb8f02 642 #+cmu(%naturalize-c-string string)
643 #+sbcl(%naturalize-utf8-string string)
508d13a7 644 (deallocate-memory string)))))
fc358945 645
6baf860c 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)
7bde5a67 653 (declare (ignore args))
6baf860c 654 #'(lambda (string)
655 (unless (null-pointer-p string)
656 (deallocate-memory string))))
657
508d13a7 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)
a9bb8f02 662 #+cmu(%naturalize-c-string string)
663 #+sbcl(%naturalize-utf8-string string))))
508d13a7 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)
a9bb8f02 669 #+cmu(%naturalize-c-string string)
670 #+sbcl(%naturalize-utf8-string string))))
508d13a7 671
6baf860c 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)
a9bb8f02 677 #+cmu
6baf860c 678 (copy-memory
3d36c5d6 679 (vector-sap (coerce string 'simple-base-string))
a9bb8f02 680 (1+ (length string)))
681 #+sbcl
682 (let ((utf8 (%deport-utf8-string string)))
683 (copy-memory (vector-sap utf8) (length utf8))))))
6baf860c 684
685(defmethod reader-function ((type (eql 'string)) &rest args)
686 (declare (ignore type args))
0739b019 687 #'(lambda (location &optional (offset 0) weak-p)
688 (declare (ignore weak-p))
6baf860c 689 (unless (null-pointer-p (sap-ref-sap location offset))
a9bb8f02 690 #+cmu(%naturalize-c-string (sap-ref-sap location offset))
691 #+sbcl(%naturalize-utf8-string (sap-ref-sap location offset)))))
6baf860c 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
b6bf802c 700(defmethod unbound-value ((type (eql 'string)) &rest args)
701 (declare (ignore type args))
702 (values t nil))
6baf860c 703
a9bb8f02 704
6baf860c 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))
fc358945 712
6baf860c 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)))
0739b019 750 #'(lambda (location &optional (offset 0) weak-p)
751 (declare (ignore weak-p))
6baf860c 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
b6bf802c 760(defmethod unbound-value ((type (eql 'pathname)) &rest args)
761 (declare (ignore type args))
762 (unbound-value 'string))
763
6baf860c 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))
fc358945 773 `(if ,boolean 1 0))
774
6baf860c 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)))
0739b019 798 #'(lambda (location &optional (offset 0) weak-p)
799 (declare (ignore weak-p))
6baf860c 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)))
fc358945 810 alien-type))
811
6baf860c 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))
fc358945 838 'system-area-pointer)
839
6baf860c 840(defmethod size-of ((type (eql 'system-area-pointer)) &rest args)
841 (declare (ignore type args))
842 +size-of-pointer+)
fc358945 843
6baf860c 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)))
fc358945 848
6baf860c 849(defmethod reader-function ((type (eql 'system-area-pointer)) &rest args)
850 (declare (ignore type args))
0739b019 851 #'(lambda (location &optional (offset 0) weak-p)
852 (declare (ignore weak-p))
6baf860c 853 (sap-ref-sap location offset)))
fc358945 854
855
6baf860c 856(defmethod alien-type ((type (eql 'null)) &rest args)
857 (declare (ignore type args))
858 (alien-type 'pointer))
fc358945 859
6baf860c 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))
fc358945 866 `(make-pointer 0))
867
6baf860c 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)))
fc358945 873
fc358945 874
6baf860c 875(defmethod alien-type ((type (eql 'nil)) &rest args)
876 (declare (ignore type args))
3d36c5d6 877 'void)
6baf860c 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)))
508d13a7 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
4c795125 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)))
ff8fa451 917
918
919(defmethod alien-type ((type (eql 'callback)) &rest args)
920 (declare (ignore type args))
921 (alien-type 'pointer))
922
ae17423c 923#+nil
ff8fa451 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))
ae17423c 930 `(callback-address ,callback))
ff8fa451 931
932(defmethod to-alien-function ((type (eql 'callback)) &rest args)
933 (declare (ignore type args))
ae17423c 934 #'callback-address)
ff8fa451 935
ae17423c 936#+nil(
ff8fa451 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)))
0739b019 962 #'(lambda (location &optional (offset 0) weak-p)
963 (declare (ignore weak-p))
ff8fa451 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))
ae17423c 971)