types.lisp - clic - Clic is an command line interactive client for gopher written in Common LISP
 (HTM) git clone git://bitreich.org/clic/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/clic/
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Tags
 (DIR) README
 (DIR) LICENSE
       ---
       types.lisp (44771B)
       ---
            1 ;;;; -*- Mode: lisp; indent-tabs-mode: nil -*-
            2 ;;;
            3 ;;; types.lisp --- User-defined CFFI types.
            4 ;;;
            5 ;;; Copyright (C) 2005-2006, James Bielman  <jamesjb@jamesjb.com>
            6 ;;; Copyright (C) 2005-2007, Luis Oliveira  <loliveira@common-lisp.net>
            7 ;;;
            8 ;;; Permission is hereby granted, free of charge, to any person
            9 ;;; obtaining a copy of this software and associated documentation
           10 ;;; files (the "Software"), to deal in the Software without
           11 ;;; restriction, including without limitation the rights to use, copy,
           12 ;;; modify, merge, publish, distribute, sublicense, and/or sell copies
           13 ;;; of the Software, and to permit persons to whom the Software is
           14 ;;; furnished to do so, subject to the following conditions:
           15 ;;;
           16 ;;; The above copyright notice and this permission notice shall be
           17 ;;; included in all copies or substantial portions of the Software.
           18 ;;;
           19 ;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
           20 ;;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
           21 ;;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
           22 ;;; NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
           23 ;;; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
           24 ;;; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
           25 ;;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
           26 ;;; DEALINGS IN THE SOFTWARE.
           27 ;;;
           28 
           29 (in-package #:cffi)
           30 
           31 ;;;# Built-In Types
           32 
           33 ;; NOTE: In the C standard there's a "signed-char":
           34 ;; https://stackoverflow.com/questions/436513/char-signed-char-char-unsigned-char
           35 ;; and "char" may be either signed or unsigned, i.e. treating it as a small int
           36 ;; is not wise. At the level of CFFI we can safely ignore this and assume that
           37 ;; :char is mapped to "signed-char" by the CL implementation under us.
           38 (define-built-in-foreign-type :char)
           39 (define-built-in-foreign-type :unsigned-char)
           40 (define-built-in-foreign-type :short)
           41 (define-built-in-foreign-type :unsigned-short)
           42 (define-built-in-foreign-type :int)
           43 (define-built-in-foreign-type :unsigned-int)
           44 (define-built-in-foreign-type :long)
           45 (define-built-in-foreign-type :unsigned-long)
           46 (define-built-in-foreign-type :float)
           47 (define-built-in-foreign-type :double)
           48 (define-built-in-foreign-type :void)
           49 
           50 #-cffi-sys::no-long-long
           51 (progn
           52   (define-built-in-foreign-type :long-long)
           53   (define-built-in-foreign-type :unsigned-long-long))
           54 
           55 ;;; Define emulated LONG-LONG types.  Needs checking whether we're
           56 ;;; using the right sizes on various platforms.
           57 ;;;
           58 ;;; A possibly better, certainly faster though more intrusive,
           59 ;;; alternative is available here:
           60 ;;;   <http://article.gmane.org/gmane.lisp.cffi.devel/1091>
           61 #+cffi-sys::no-long-long
           62 (eval-when (:compile-toplevel :load-toplevel :execute)
           63   (defclass emulated-llong-type (foreign-type) ())
           64   (defmethod foreign-type-size ((tp emulated-llong-type)) 8)
           65   (defmethod foreign-type-alignment ((tp emulated-llong-type))
           66     ;; better than assuming that the alignment is 8
           67     (foreign-type-alignment :long))
           68   (defmethod aggregatep ((tp emulated-llong-type)) nil)
           69 
           70   (define-foreign-type emulated-llong (emulated-llong-type)
           71     ()
           72     (:simple-parser :long-long))
           73 
           74   (define-foreign-type emulated-ullong (emulated-llong-type)
           75     ()
           76     (:simple-parser :unsigned-long-long))
           77 
           78   (defmethod canonicalize ((tp emulated-llong)) :long-long)
           79   (defmethod unparse-type ((tp emulated-llong)) :long-long)
           80   (defmethod canonicalize ((tp emulated-ullong)) :unsigned-long-long)
           81   (defmethod unparse-type ((tp emulated-ullong)) :unsigned-long-long)
           82 
           83   (defun %emulated-mem-ref-64 (ptr type offset)
           84     (let ((value #+big-endian
           85                  (+ (ash (mem-ref ptr :unsigned-long offset) 32)
           86                     (mem-ref ptr :unsigned-long (+ offset 4)))
           87                  #+little-endian
           88                  (+ (mem-ref ptr :unsigned-long offset)
           89                     (ash (mem-ref ptr :unsigned-long (+ offset 4)) 32))))
           90       (if (and (eq type :long-long) (logbitp 63 value))
           91           (lognot (logxor value #xFFFFFFFFFFFFFFFF))
           92           value)))
           93 
           94   (defun %emulated-mem-set-64 (value ptr type offset)
           95     (when (and (eq type :long-long) (minusp value))
           96       (setq value (lognot (logxor value #xFFFFFFFFFFFFFFFF))))
           97     (%mem-set (ldb (byte 32 0) value) ptr :unsigned-long
           98               #+big-endian (+ offset 4) #+little-endian offset)
           99     (%mem-set (ldb (byte 32 32) value) ptr :unsigned-long
          100               #+big-endian offset #+little-endian (+ offset 4))
          101     value))
          102 
          103 ;;; When some lisp other than SCL supports :long-double we should
          104 ;;; use #-cffi-sys::no-long-double here instead.
          105 #+(and scl long-float) (define-built-in-foreign-type :long-double)
          106 
          107 (defparameter *possible-float-types* '(:float :double :long-double))
          108 
          109 (defparameter *other-builtin-types* '(:pointer :void)
          110   "List of types other than integer or float built in to CFFI.")
          111 
          112 (defparameter *built-in-integer-types*
          113   (set-difference
          114    cffi:*built-in-foreign-types*
          115    (append *possible-float-types* *other-builtin-types*))
          116   "List of integer types supported by CFFI.")
          117 
          118 (defparameter *built-in-float-types*
          119   (set-difference
          120    cffi:*built-in-foreign-types*
          121    (append *built-in-integer-types* *other-builtin-types*))
          122   "List of real float types supported by CFFI.")
          123 
          124 ;;;# Foreign Pointers
          125 
          126 (define-compiler-macro inc-pointer (&whole form pointer offset)
          127   (if (and (constantp offset)
          128            (eql 0 (eval offset)))
          129       pointer
          130       form))
          131 
          132 (define-modify-macro incf-pointer (&optional (offset 1)) inc-pointer)
          133 
          134 (defun mem-ref (ptr type &optional (offset 0))
          135   "Return the value of TYPE at OFFSET bytes from PTR. If TYPE is aggregate,
          136 we don't return its 'value' but a pointer to it, which is PTR itself."
          137   (let* ((parsed-type (parse-type type))
          138          (ctype (canonicalize parsed-type)))
          139           #+cffi-sys::no-long-long
          140           (when (member ctype '(:long-long :unsigned-long-long))
          141             (return-from mem-ref
          142               (translate-from-foreign (%emulated-mem-ref-64 ptr ctype offset)
          143                                       parsed-type)))
          144           ;; normal branch
          145     (if (aggregatep parsed-type)
          146         (if (bare-struct-type-p parsed-type)
          147             (inc-pointer ptr offset)
          148             (translate-from-foreign (inc-pointer ptr offset) parsed-type))
          149         (translate-from-foreign (%mem-ref ptr ctype offset) parsed-type))))
          150 
          151 (define-compiler-macro mem-ref (&whole form ptr type &optional (offset 0))
          152   "Compiler macro to open-code MEM-REF when TYPE is constant."
          153   (if (constantp type)
          154       (let* ((parsed-type (parse-type (eval type)))
          155              (ctype (canonicalize parsed-type)))
          156         ;; Bail out when using emulated long long types.
          157         #+cffi-sys::no-long-long
          158         (when (member ctype '(:long-long :unsigned-long-long))
          159           (return-from mem-ref form))
          160         (if (aggregatep parsed-type)
          161             (if (bare-struct-type-p parsed-type)
          162                 `(inc-pointer ,ptr ,offset)
          163                 (expand-from-foreign `(inc-pointer ,ptr ,offset) parsed-type))
          164             (expand-from-foreign `(%mem-ref ,ptr ,ctype ,offset) parsed-type)))
          165       form))
          166 
          167 (defun mem-set (value ptr type &optional (offset 0))
          168   "Set the value of TYPE at OFFSET bytes from PTR to VALUE."
          169   (let* ((ptype (parse-type type))
          170          (ctype (canonicalize ptype)))
          171     #+cffi-sys::no-long-long
          172     (when (or (eq ctype :long-long) (eq ctype :unsigned-long-long))
          173       (return-from mem-set
          174         (%emulated-mem-set-64 (translate-to-foreign value ptype)
          175                               ptr ctype offset)))
          176     (if (aggregatep ptype) ; XXX: backwards incompatible?
          177         (translate-into-foreign-memory value ptype (inc-pointer ptr offset))
          178         (%mem-set (translate-to-foreign value ptype) ptr ctype offset))))
          179 
          180 (define-setf-expander mem-ref (ptr type &optional (offset 0) &environment env)
          181   "SETF expander for MEM-REF that doesn't rebind TYPE.
          182 This is necessary for the compiler macro on MEM-SET to be able
          183 to open-code (SETF MEM-REF) forms."
          184   (multiple-value-bind (dummies vals newval setter getter)
          185       (get-setf-expansion ptr env)
          186     (declare (ignore setter newval))
          187     ;; if either TYPE or OFFSET are constant, we avoid rebinding them
          188     ;; so that the compiler macros on MEM-SET and %MEM-SET work.
          189     (with-unique-names (store type-tmp offset-tmp)
          190       (values
          191        (append (unless (constantp type)   (list type-tmp))
          192                (unless (constantp offset) (list offset-tmp))
          193                dummies)
          194        (append (unless (constantp type)   (list type))
          195                (unless (constantp offset) (list offset))
          196                vals)
          197        (list store)
          198        `(progn
          199           (mem-set ,store ,getter
          200                    ,@(if (constantp type)   (list type)   (list type-tmp))
          201                    ,@(if (constantp offset) (list offset) (list offset-tmp)))
          202           ,store)
          203        `(mem-ref ,getter
          204                  ,@(if (constantp type)   (list type)   (list type-tmp))
          205                  ,@(if (constantp offset) (list offset) (list offset-tmp)))))))
          206 
          207 (define-compiler-macro mem-set
          208     (&whole form value ptr type &optional (offset 0))
          209   "Compiler macro to open-code (SETF MEM-REF) when type is constant."
          210   (if (constantp type)
          211       (let* ((parsed-type (parse-type (eval type)))
          212              (ctype (canonicalize parsed-type)))
          213         ;; Bail out when using emulated long long types.
          214         #+cffi-sys::no-long-long
          215         (when (member ctype '(:long-long :unsigned-long-long))
          216           (return-from mem-set form))
          217         (if (aggregatep parsed-type)
          218             (expand-into-foreign-memory
          219              value parsed-type `(inc-pointer ,ptr ,offset))
          220             `(%mem-set ,(expand-to-foreign value parsed-type)
          221                        ,ptr ,ctype ,offset)))
          222       form))
          223 
          224 ;;;# Dereferencing Foreign Arrays
          225 
          226 ;;; Maybe this should be named MEM-SVREF? [2007-02-28 LO]
          227 (defun mem-aref (ptr type &optional (index 0))
          228   "Like MEM-REF except for accessing 1d arrays."
          229   (mem-ref ptr type (* index (foreign-type-size type))))
          230 
          231 (define-compiler-macro mem-aref (&whole form ptr type &optional (index 0))
          232   "Compiler macro to open-code MEM-AREF when TYPE (and eventually INDEX)."
          233   (if (constantp type)
          234       (if (constantp index)
          235           `(mem-ref ,ptr ,type
          236                     ,(* (eval index) (foreign-type-size (eval type))))
          237           `(mem-ref ,ptr ,type (* ,index ,(foreign-type-size (eval type)))))
          238       form))
          239 
          240 (define-setf-expander mem-aref (ptr type &optional (index 0) &environment env)
          241   "SETF expander for MEM-AREF."
          242   (multiple-value-bind (dummies vals newval setter getter)
          243       (get-setf-expansion ptr env)
          244     (declare (ignore setter newval))
          245     ;; we avoid rebinding type and index, if possible (and if type is not
          246     ;; constant, we don't bother about the index), so that the compiler macros
          247     ;; on MEM-SET or %MEM-SET can work.
          248     (with-unique-names (store type-tmp index-tmp)
          249       (values
          250        (append (unless (constantp type)
          251                  (list type-tmp))
          252                (unless (and (constantp type) (constantp index))
          253                  (list index-tmp))
          254                dummies)
          255        (append (unless (constantp type)
          256                  (list type))
          257                (unless (and (constantp type) (constantp index))
          258                  (list index))
          259                vals)
          260        (list store)
          261        ;; Here we'll try to calculate the offset from the type and index,
          262        ;; or if not possible at least get the type size early.
          263        `(progn
          264           ,(if (constantp type)
          265                (if (constantp index)
          266                    `(mem-set ,store ,getter ,type
          267                              ,(* (eval index) (foreign-type-size (eval type))))
          268                    `(mem-set ,store ,getter ,type
          269                              (* ,index-tmp ,(foreign-type-size (eval type)))))
          270                `(mem-set ,store ,getter ,type-tmp
          271                          (* ,index-tmp (foreign-type-size ,type-tmp))))
          272           ,store)
          273        `(mem-aref ,getter
          274                   ,@(if (constantp type)
          275                         (list type)
          276                         (list type-tmp))
          277                   ,@(if (and (constantp type) (constantp index))
          278                         (list index)
          279                         (list index-tmp)))))))
          280 
          281 (defmethod translate-into-foreign-memory
          282     (value (type foreign-pointer-type) pointer)
          283   (setf (mem-aref pointer :pointer) value))
          284 
          285 (defmethod translate-into-foreign-memory
          286     (value (type foreign-built-in-type) pointer)
          287   (setf (mem-aref pointer (unparse-type type)) value))
          288 
          289 (defun mem-aptr (ptr type &optional (index 0))
          290   "The pointer to the element."
          291   (inc-pointer ptr (* index (foreign-type-size type))))
          292 
          293 (define-compiler-macro mem-aptr (&whole form ptr type &optional (index 0))
          294   "The pointer to the element."
          295   (cond ((not (constantp type))
          296          form)
          297         ((not (constantp index))
          298          `(inc-pointer ,ptr (* ,index ,(foreign-type-size (eval type)))))
          299         ((zerop (eval index))
          300          ptr)
          301         (t
          302          `(inc-pointer ,ptr ,(* (eval index)
          303                                 (foreign-type-size (eval type)))))))
          304 
          305 (define-foreign-type foreign-array-type ()
          306   ((dimensions :reader dimensions :initarg :dimensions)
          307    (element-type :reader element-type :initarg :element-type))
          308   (:actual-type :pointer))
          309 
          310 (defmethod aggregatep ((type foreign-array-type))
          311   t)
          312 
          313 (defmethod print-object ((type foreign-array-type) stream)
          314   "Print a FOREIGN-ARRAY-TYPE instance to STREAM unreadably."
          315   (print-unreadable-object (type stream :type t :identity nil)
          316     (format stream "~S ~S" (element-type type) (dimensions type))))
          317 
          318 (defun array-element-size (array-type)
          319   (foreign-type-size (element-type array-type)))
          320 
          321 (defmethod foreign-type-size ((type foreign-array-type))
          322   (* (array-element-size type) (reduce #'* (dimensions type))))
          323 
          324 (defmethod foreign-type-alignment ((type foreign-array-type))
          325   (foreign-type-alignment (element-type type)))
          326 
          327 (define-parse-method :array (element-type &rest dimensions)
          328   (assert (plusp (length dimensions)))
          329   (make-instance 'foreign-array-type
          330                  :element-type element-type
          331                  :dimensions dimensions))
          332 
          333 (defun indexes-to-row-major-index (dimensions &rest subscripts)
          334   (apply #'+ (maplist (lambda (x y)
          335                         (* (car x) (apply #'* (cdr y))))
          336                       subscripts
          337                       dimensions)))
          338 
          339 (defun row-major-index-to-indexes (index dimensions)
          340   (loop with idx = index
          341         with rank = (length dimensions)
          342         with indexes = (make-list rank)
          343         for dim-index from (- rank 1) downto 0 do
          344         (setf (values idx (nth dim-index indexes))
          345               (floor idx (nth dim-index dimensions)))
          346         finally (return indexes)))
          347 
          348 (defun foreign-alloc (type &key (initial-element nil initial-element-p)
          349                       (initial-contents nil initial-contents-p)
          350                       (count 1 count-p) null-terminated-p)
          351   "Allocate enough memory to hold COUNT objects of type TYPE. If
          352 INITIAL-ELEMENT is supplied, each element of the newly allocated
          353 memory is initialized with its value. If INITIAL-CONTENTS is supplied,
          354 each of its elements will be used to initialize the contents of the
          355 newly allocated memory."
          356   (let (contents-length)
          357     ;; Some error checking, etc...
          358     (when (and null-terminated-p
          359                (not (eq (canonicalize-foreign-type type) :pointer)))
          360       (error "Cannot use :NULL-TERMINATED-P with non-pointer types."))
          361     (when (and initial-element-p initial-contents-p)
          362       (error "Cannot specify both :INITIAL-ELEMENT and :INITIAL-CONTENTS"))
          363     (when initial-contents-p
          364       (setq contents-length (length initial-contents))
          365       (if count-p
          366           (assert (>= count contents-length))
          367           (setq count contents-length)))
          368     ;; Everything looks good.
          369     (let ((ptr (%foreign-alloc (* (foreign-type-size type)
          370                                   (if null-terminated-p (1+ count) count)))))
          371       (when initial-element-p
          372         (dotimes (i count)
          373           (setf (mem-aref ptr type i) initial-element)))
          374       (when initial-contents-p
          375         (dotimes (i contents-length)
          376           (setf (mem-aref ptr type i) (elt initial-contents i))))
          377       (when null-terminated-p
          378         (setf (mem-aref ptr :pointer count) (null-pointer)))
          379       ptr)))
          380 
          381 ;;; Simple compiler macro that kicks in when TYPE is constant and only
          382 ;;; the COUNT argument is passed.  (Note: hard-coding the type's size
          383 ;;; into the fasl will likely break CLISP fasl cross-platform
          384 ;;; compatibilty.)
          385 (define-compiler-macro foreign-alloc (&whole form type &rest args
          386                                       &key (count 1 count-p) &allow-other-keys)
          387   (if (or (and count-p (<= (length args) 2)) (null args))
          388       (cond
          389         ((and (constantp type) (constantp count))
          390          `(%foreign-alloc ,(* (eval count) (foreign-type-size (eval type)))))
          391         ((constantp type)
          392          `(%foreign-alloc (* ,count ,(foreign-type-size (eval type)))))
          393         (t form))
          394       form))
          395 
          396 (defun lisp-array-to-foreign (array pointer array-type)
          397   "Copy elements from a Lisp array to POINTER. ARRAY-TYPE must be a CFFI array
          398 type."
          399   (let* ((type (ensure-parsed-base-type array-type))
          400          (el-type (element-type type))
          401          (dimensions (dimensions type)))
          402     (loop with foreign-type-size = (array-element-size type)
          403           with size = (reduce #'* dimensions)
          404           for i from 0 below size
          405           for offset = (* i foreign-type-size)
          406           for element = (apply #'aref array
          407                                (row-major-index-to-indexes i dimensions))
          408           do (setf (mem-ref pointer el-type offset) element))))
          409 
          410 (defun foreign-array-to-lisp (pointer array-type &rest make-array-args)
          411   "Copy elements from pointer into a Lisp array. ARRAY-TYPE must be a CFFI array
          412 type; the type of the resulting Lisp array can be defined in MAKE-ARRAY-ARGS
          413 that are then passed to MAKE-ARRAY. If POINTER is a null pointer, returns NIL."
          414   (unless (null-pointer-p pointer)
          415     (let* ((type (ensure-parsed-base-type array-type))
          416            (el-type (element-type type))
          417            (dimensions (dimensions type))
          418            (array (apply #'make-array dimensions make-array-args)))
          419       (loop with foreign-type-size = (array-element-size type)
          420             with size = (reduce #'* dimensions)
          421             for i from 0 below size
          422             for offset = (* i foreign-type-size)
          423             for element = (mem-ref pointer el-type offset)
          424             do (setf (apply #'aref array
          425                             (row-major-index-to-indexes i dimensions))
          426                      element))
          427       array)))
          428 
          429 (defun foreign-array-alloc (array array-type)
          430   "Allocate a foreign array containing the elements of lisp array.
          431 The foreign array must be freed with foreign-array-free."
          432   (check-type array array)
          433   (let* ((type (ensure-parsed-base-type array-type))
          434          (ptr (foreign-alloc (element-type type)
          435                              :count (reduce #'* (dimensions type)))))
          436     (lisp-array-to-foreign array ptr array-type)
          437     ptr))
          438 
          439 (defun foreign-array-free (ptr)
          440   "Free a foreign array allocated by foreign-array-alloc."
          441   (foreign-free ptr))
          442 
          443 (defmacro with-foreign-array ((var lisp-array array-type) &body body)
          444   "Bind var to a foreign array containing lisp-array elements in body."
          445   (with-unique-names (type)
          446     `(let ((,type (ensure-parsed-base-type ,array-type)))
          447        (with-foreign-pointer (,var (* (reduce #'* (dimensions ,type))
          448                                       (array-element-size ,type)))
          449          (lisp-array-to-foreign ,lisp-array ,var ,array-type)
          450          ,@body))))
          451 
          452 (defun foreign-aref (ptr array-type &rest indexes)
          453   (let* ((type (ensure-parsed-base-type array-type))
          454          (offset (* (array-element-size type)
          455                     (apply #'indexes-to-row-major-index
          456                            (dimensions type) indexes))))
          457     (mem-ref ptr (element-type type) offset)))
          458 
          459 (defun (setf foreign-aref) (value ptr array-type &rest indexes)
          460   (let* ((type (ensure-parsed-base-type array-type))
          461          (offset (* (array-element-size type)
          462                     (apply #'indexes-to-row-major-index
          463                            (dimensions type) indexes))))
          464     (setf (mem-ref ptr (element-type type) offset) value)))
          465 
          466 ;;; Automatic translations for the :ARRAY type. Notice that these
          467 ;;; translators will also invoke the appropriate translators for for
          468 ;;; each of the array's elements since that's the normal behaviour of
          469 ;;; the FOREIGN-ARRAY-* operators, but there's a FIXME: **it doesn't
          470 ;;; free them yet**
          471 
          472 ;;; This used to be in a separate type but let's experiment with just
          473 ;;; one type for a while. [2008-12-30 LO]
          474 
          475 ;;; FIXME: those ugly invocations of UNPARSE-TYPE suggest that these
          476 ;;; foreign array operators should take the type and dimention
          477 ;;; arguments "unboxed". [2008-12-31 LO]
          478 
          479 (defmethod translate-to-foreign (array (type foreign-array-type))
          480   (foreign-array-alloc array (unparse-type type)))
          481 
          482 (defmethod translate-aggregate-to-foreign (ptr value (type foreign-array-type))
          483   (lisp-array-to-foreign value ptr (unparse-type type)))
          484 
          485 (defmethod translate-from-foreign (pointer (type foreign-array-type))
          486   (foreign-array-to-lisp pointer (unparse-type type)))
          487 
          488 (defmethod free-translated-object (pointer (type foreign-array-type) param)
          489   (declare (ignore param))
          490   (foreign-array-free pointer))
          491 
          492 ;;;# Foreign Structures
          493 
          494 ;;;## Foreign Structure Slots
          495 
          496 (defgeneric foreign-struct-slot-pointer (ptr slot)
          497   (:documentation
          498    "Get the address of SLOT relative to PTR."))
          499 
          500 (defgeneric foreign-struct-slot-pointer-form (ptr slot)
          501   (:documentation
          502    "Return a form to get the address of SLOT in PTR."))
          503 
          504 (defgeneric foreign-struct-slot-value (ptr slot)
          505   (:documentation
          506    "Return the value of SLOT in structure PTR."))
          507 
          508 (defgeneric (setf foreign-struct-slot-value) (value ptr slot)
          509   (:documentation
          510    "Set the value of a SLOT in structure PTR."))
          511 
          512 (defgeneric foreign-struct-slot-value-form (ptr slot)
          513   (:documentation
          514    "Return a form to get the value of SLOT in struct PTR."))
          515 
          516 (defgeneric foreign-struct-slot-set-form (value ptr slot)
          517   (:documentation
          518    "Return a form to set the value of SLOT in struct PTR."))
          519 
          520 (defclass foreign-struct-slot ()
          521   ((name   :initarg :name   :reader   slot-name)
          522    (offset :initarg :offset :accessor slot-offset)
          523    ;; FIXME: the type should probably be parsed?
          524    (type   :initarg :type   :accessor slot-type))
          525   (:documentation "Base class for simple and aggregate slots."))
          526 
          527 (defmethod foreign-struct-slot-pointer (ptr (slot foreign-struct-slot))
          528   "Return the address of SLOT relative to PTR."
          529   (inc-pointer ptr (slot-offset slot)))
          530 
          531 (defmethod foreign-struct-slot-pointer-form (ptr (slot foreign-struct-slot))
          532   "Return a form to get the address of SLOT relative to PTR."
          533   (let ((offset (slot-offset slot)))
          534     (if (zerop offset)
          535         ptr
          536         `(inc-pointer ,ptr ,offset))))
          537 
          538 (defun foreign-slot-names (type)
          539   "Returns a list of TYPE's slot names in no particular order."
          540   (loop for value being the hash-values
          541         in (slots (ensure-parsed-base-type type))
          542         collect (slot-name value)))
          543 
          544 ;;;### Simple Slots
          545 
          546 (defclass simple-struct-slot (foreign-struct-slot)
          547   ()
          548   (:documentation "Non-aggregate structure slots."))
          549 
          550 (defmethod foreign-struct-slot-value (ptr (slot simple-struct-slot))
          551   "Return the value of a simple SLOT from a struct at PTR."
          552   (mem-ref ptr (slot-type slot) (slot-offset slot)))
          553 
          554 (defmethod foreign-struct-slot-value-form (ptr (slot simple-struct-slot))
          555   "Return a form to get the value of a slot from PTR."
          556   `(mem-ref ,ptr ',(slot-type slot) ,(slot-offset slot)))
          557 
          558 (defmethod (setf foreign-struct-slot-value) (value ptr (slot simple-struct-slot))
          559   "Set the value of a simple SLOT to VALUE in PTR."
          560   (setf (mem-ref ptr (slot-type slot) (slot-offset slot)) value))
          561 
          562 (defmethod foreign-struct-slot-set-form (value ptr (slot simple-struct-slot))
          563   "Return a form to set the value of a simple structure slot."
          564   `(setf (mem-ref ,ptr ',(slot-type slot) ,(slot-offset slot)) ,value))
          565 
          566 ;;;### Aggregate Slots
          567 
          568 (defclass aggregate-struct-slot (foreign-struct-slot)
          569   ((count :initarg :count :accessor slot-count))
          570   (:documentation "Aggregate structure slots."))
          571 
          572 ;;; Since MEM-REF returns a pointer for struct types we are able to
          573 ;;; chain together slot names when accessing slot values in nested
          574 ;;; structures.
          575 (defmethod foreign-struct-slot-value (ptr (slot aggregate-struct-slot))
          576   "Return a pointer to SLOT relative to PTR."
          577   (convert-from-foreign (inc-pointer ptr (slot-offset slot))
          578                         (slot-type slot)))
          579 
          580 (defmethod foreign-struct-slot-value-form (ptr (slot aggregate-struct-slot))
          581   "Return a form to get the value of SLOT relative to PTR."
          582   `(convert-from-foreign (inc-pointer ,ptr ,(slot-offset slot))
          583                          ',(slot-type slot)))
          584 
          585 (defmethod translate-aggregate-to-foreign (ptr value (type foreign-struct-type))
          586   ;;; FIXME: use the block memory interface instead.
          587   (loop for i below (foreign-type-size type)
          588         do (%mem-set (%mem-ref value :char i) ptr :char i)))
          589 
          590 (defmethod (setf foreign-struct-slot-value)
          591     (value ptr (slot aggregate-struct-slot))
          592   "Set the value of an aggregate SLOT to VALUE in PTR."
          593   (translate-aggregate-to-foreign (inc-pointer ptr (slot-offset slot))
          594                                   value
          595                                   (parse-type (slot-type slot))))
          596 
          597 (defmethod foreign-struct-slot-set-form (value ptr (slot aggregate-struct-slot))
          598   "Return a form to get the value of an aggregate SLOT relative to PTR."
          599   `(translate-aggregate-to-foreign (inc-pointer ,ptr ,(slot-offset slot))
          600                                    ,value
          601                                    ,(parse-type (slot-type slot))))
          602 
          603 ;;;## Defining Foreign Structures
          604 
          605 (defun make-struct-slot (name offset type count)
          606   "Make the appropriate type of structure slot."
          607   ;; If TYPE is an aggregate type or COUNT is >1, create an
          608   ;; AGGREGATE-STRUCT-SLOT, otherwise a SIMPLE-STRUCT-SLOT.
          609   (if (or (> count 1) (aggregatep (parse-type type)))
          610       (make-instance 'aggregate-struct-slot :offset offset :type type
          611                      :name name :count count)
          612       (make-instance 'simple-struct-slot :offset offset :type type
          613                      :name name)))
          614 
          615 (defun parse-deprecated-struct-type (name struct-or-union)
          616   (check-type struct-or-union (member :struct :union))
          617   (let* ((struct-type-name `(,struct-or-union ,name))
          618          (struct-type (parse-type struct-type-name)))
          619     (simple-style-warning
          620      "bare references to struct types are deprecated. ~
          621       Please use ~S or ~S instead."
          622      `(:pointer ,struct-type-name) struct-type-name)
          623     (make-instance (class-of struct-type)
          624                    :alignment (alignment struct-type)
          625                    :size (size struct-type)
          626                    :slots (slots struct-type)
          627                    :name (name struct-type)
          628                    :bare t)))
          629 
          630 ;;; Regarding structure alignment, the following ABIs were checked:
          631 ;;;   - System-V ABI: x86, x86-64, ppc, arm, mips and itanium. (more?)
          632 ;;;   - Mac OS X ABI Function Call Guide: ppc32, ppc64 and x86.
          633 ;;;
          634 ;;; Rules used here:
          635 ;;;
          636 ;;;   1. "An entire structure or union object is aligned on the same
          637 ;;;       boundary as its most strictly aligned member."
          638 ;;;
          639 ;;;   2. "Each member is assigned to the lowest available offset with
          640 ;;;       the appropriate alignment. This may require internal
          641 ;;;       padding, depending on the previous member."
          642 ;;;
          643 ;;;   3. "A structure's size is increased, if necessary, to make it a
          644 ;;;       multiple of the alignment. This may require tail padding,
          645 ;;;       depending on the last member."
          646 ;;;
          647 ;;; Special cases from darwin/ppc32's ABI:
          648 ;;; http://developer.apple.com/documentation/DeveloperTools/Conceptual/LowLevelABI/index.html
          649 ;;;
          650 ;;;   4. "The embedding alignment of the first element in a data
          651 ;;;       structure is equal to the element's natural alignment."
          652 ;;;
          653 ;;;   5. "For subsequent elements that have a natural alignment
          654 ;;;       greater than 4 bytes, the embedding alignment is 4, unless
          655 ;;;       the element is a vector."  (note: this applies for
          656 ;;;       structures too)
          657 
          658 ;; FIXME: get a better name for this. --luis
          659 (defun get-alignment (type alignment-type firstp)
          660   "Return alignment for TYPE according to ALIGNMENT-TYPE."
          661   (declare (ignorable firstp))
          662   (ecase alignment-type
          663     (:normal #-(and darwin ppc)
          664              (foreign-type-alignment type)
          665              #+(and darwin ppc)
          666              (if firstp
          667                  (foreign-type-alignment type)
          668                  (min 4 (foreign-type-alignment type))))))
          669 
          670 (defun adjust-for-alignment (type offset alignment-type firstp)
          671   "Return OFFSET aligned properly for TYPE according to ALIGNMENT-TYPE."
          672   (let* ((align (get-alignment type alignment-type firstp))
          673          (rem (mod offset align)))
          674     (if (zerop rem)
          675         offset
          676         (+ offset (- align rem)))))
          677 
          678 (defmacro with-tentative-type-definition ((name value namespace) &body body)
          679   (once-only (name namespace)
          680     `(unwind-protect-case ()
          681           (progn
          682             (notice-foreign-type ,name ,value ,namespace)
          683             ,@body)
          684        (:abort (undefine-foreign-type ,name ,namespace)))))
          685 
          686 (defun notice-foreign-struct-definition (name options slots)
          687   "Parse and install a foreign structure definition."
          688   (destructuring-bind (&key size (class 'foreign-struct-type))
          689       options
          690     (let ((struct (make-instance class :name name))
          691           (current-offset 0)
          692           (max-align 1)
          693           (firstp t))
          694       (with-tentative-type-definition (name struct :struct)
          695         ;; determine offsets
          696         (dolist (slotdef slots)
          697           (destructuring-bind (slotname type &key (count 1) offset) slotdef
          698             (when (eq (canonicalize-foreign-type type) :void)
          699               (simple-foreign-type-error type :struct
          700                                          "In struct ~S: void type not allowed in field ~S"
          701                                          name slotdef))
          702             (setq current-offset
          703                   (or offset
          704                       (adjust-for-alignment type current-offset :normal firstp)))
          705             (let* ((slot (make-struct-slot slotname current-offset type count))
          706                    (align (get-alignment (slot-type slot) :normal firstp)))
          707               (setf (gethash slotname (slots struct)) slot)
          708               (when (> align max-align)
          709                 (setq max-align align)))
          710             (incf current-offset (* count (foreign-type-size type))))
          711           (setq firstp nil))
          712         ;; calculate padding and alignment
          713         (setf (alignment struct) max-align) ; See point 1 above.
          714         (let ((tail-padding (- max-align (rem current-offset max-align))))
          715           (unless (= tail-padding max-align) ; See point 3 above.
          716             (incf current-offset tail-padding)))
          717         (setf (size struct) (or size current-offset))))))
          718 
          719 (defun generate-struct-accessors (name conc-name slot-names)
          720   (loop with pointer-arg = (symbolicate '#:pointer-to- name)
          721         for slot in slot-names
          722         for accessor = (symbolicate conc-name slot)
          723         collect `(defun ,accessor (,pointer-arg)
          724                    (foreign-slot-value ,pointer-arg '(:struct ,name) ',slot))
          725         collect `(defun (setf ,accessor) (value ,pointer-arg)
          726                    (foreign-slot-set value ,pointer-arg '(:struct ,name) ',slot))))
          727 
          728 (define-parse-method :struct (name)
          729   (funcall (find-type-parser name :struct)))
          730 
          731 (defvar *defcstruct-hook* nil)
          732 
          733 (defmacro defcstruct (name-and-options &body fields)
          734   "Define the layout of a foreign structure."
          735   (discard-docstring fields)
          736   (destructuring-bind (name . options)
          737       (ensure-list name-and-options)
          738     (let ((conc-name (getf options :conc-name)))
          739       (remf options :conc-name)
          740       (unless (getf options :class) (setf (getf options :class) (symbolicate name '-tclass)))
          741       `(eval-when (:compile-toplevel :load-toplevel :execute)
          742          ;; m-f-s-t could do with this with mop:ensure-class.
          743          ,(when-let (class (getf options :class))
          744             `(defclass ,class (foreign-struct-type
          745                                translatable-foreign-type)
          746                ()))
          747          (notice-foreign-struct-definition ',name ',options ',fields)
          748          ,@(when conc-name
          749              (generate-struct-accessors name conc-name
          750                                         (mapcar #'car fields)))
          751          ,@(when *defcstruct-hook*
          752              ;; If non-nil, *defcstruct-hook* should be a function
          753              ;; of the arguments that returns NIL or a list of
          754              ;; forms to include in the expansion.
          755              (apply *defcstruct-hook* name-and-options fields))
          756          (define-parse-method ,name ()
          757            (parse-deprecated-struct-type ',name :struct))
          758          '(:struct ,name)))))
          759 
          760 ;;;## Accessing Foreign Structure Slots
          761 
          762 (defun get-slot-info (type slot-name)
          763   "Return the slot info for SLOT-NAME or raise an error."
          764   (let* ((struct (ensure-parsed-base-type type))
          765          (info (gethash slot-name (slots struct))))
          766     (unless info
          767       (simple-foreign-type-error type :struct
          768                                  "Undefined slot ~A in foreign type ~A."
          769                                  slot-name type))
          770     info))
          771 
          772 (defun foreign-slot-pointer (ptr type slot-name)
          773   "Return the address of SLOT-NAME in the structure at PTR."
          774   (foreign-struct-slot-pointer ptr (get-slot-info type slot-name)))
          775 
          776 (define-compiler-macro foreign-slot-pointer (&whole whole ptr type slot-name)
          777   (if (and (constantp type) (constantp slot-name))
          778       (foreign-struct-slot-pointer-form
          779        ptr (get-slot-info (eval type) (eval slot-name)))
          780       whole))
          781 
          782 (defun foreign-slot-type (type slot-name)
          783   "Return the type of SLOT in a struct TYPE."
          784   (slot-type (get-slot-info type slot-name)))
          785 
          786 (defun foreign-slot-offset (type slot-name)
          787   "Return the offset of SLOT in a struct TYPE."
          788   (slot-offset (get-slot-info type slot-name)))
          789 
          790 (defun foreign-slot-count (type slot-name)
          791   "Return the number of items in SLOT in a struct TYPE."
          792   (slot-count (get-slot-info type slot-name)))
          793 
          794 (defun foreign-slot-value (ptr type slot-name)
          795   "Return the value of SLOT-NAME in the foreign structure at PTR."
          796   (foreign-struct-slot-value ptr (get-slot-info type slot-name)))
          797 
          798 (define-compiler-macro foreign-slot-value (&whole form ptr type slot-name)
          799   "Optimizer for FOREIGN-SLOT-VALUE when TYPE is constant."
          800   (if (and (constantp type) (constantp slot-name))
          801       (foreign-struct-slot-value-form
          802        ptr (get-slot-info (eval type) (eval slot-name)))
          803       form))
          804 
          805 (define-setf-expander foreign-slot-value (ptr type slot-name &environment env)
          806   "SETF expander for FOREIGN-SLOT-VALUE."
          807   (multiple-value-bind (dummies vals newval setter getter)
          808       (get-setf-expansion ptr env)
          809     (declare (ignore setter newval))
          810     (if (and (constantp type) (constantp slot-name))
          811         ;; if TYPE and SLOT-NAME are constant we avoid rebinding them
          812         ;; so that the compiler macro on FOREIGN-SLOT-SET works.
          813         (with-unique-names (store)
          814           (values
          815            dummies
          816            vals
          817            (list store)
          818            `(progn
          819               (foreign-slot-set ,store ,getter ,type ,slot-name)
          820               ,store)
          821            `(foreign-slot-value ,getter ,type ,slot-name)))
          822         ;; if not...
          823         (with-unique-names (store slot-name-tmp type-tmp)
          824           (values
          825            (list* type-tmp slot-name-tmp dummies)
          826            (list* type slot-name vals)
          827            (list store)
          828            `(progn
          829               (foreign-slot-set ,store ,getter ,type-tmp ,slot-name-tmp)
          830               ,store)
          831            `(foreign-slot-value ,getter ,type-tmp ,slot-name-tmp))))))
          832 
          833 (defun foreign-slot-set (value ptr type slot-name)
          834   "Set the value of SLOT-NAME in a foreign structure."
          835   (setf (foreign-struct-slot-value ptr (get-slot-info type slot-name)) value))
          836 
          837 (define-compiler-macro foreign-slot-set
          838     (&whole form value ptr type slot-name)
          839   "Optimizer when TYPE and SLOT-NAME are constant."
          840   (if (and (constantp type) (constantp slot-name))
          841       (foreign-struct-slot-set-form
          842        value ptr (get-slot-info (eval type) (eval slot-name)))
          843       form))
          844 
          845 (defmacro with-foreign-slots ((vars ptr type) &body body)
          846   "Create local symbol macros for each var in VARS to reference
          847 foreign slots in PTR of TYPE. Similar to WITH-SLOTS.
          848 Each var can be of the form: slot-name - in which case slot-name will
          849 be bound to the value of the slot or: (:pointer slot-name) - in which
          850 case slot-name will be bound to the pointer to that slot."
          851   (let ((ptr-var (gensym "PTR")))
          852     `(let ((,ptr-var ,ptr))
          853        (symbol-macrolet
          854            ,(loop :for var :in vars
          855               :collect
          856               (if (listp var)
          857                   (if (eq (first var) :pointer)
          858                       `(,(second var) (foreign-slot-pointer
          859                                        ,ptr-var ',type ',(second var)))
          860                       (error
          861                        "Malformed slot specification ~a; must be:`name' or `(:pointer name)'"
          862                        var))
          863                   `(,var (foreign-slot-value ,ptr-var ',type ',var))))
          864          ,@body))))
          865 
          866 ;;; We could add an option to define a struct instead of a class, in
          867 ;;; the unlikely event someone needs something like that.
          868 (defmacro define-c-struct-wrapper (class-and-type supers &optional slots)
          869   "Define a new class with CLOS slots matching those of a foreign
          870 struct type.  An INITIALIZE-INSTANCE method is defined which
          871 takes a :POINTER initarg that is used to store the slots of a
          872 foreign object.  This pointer is only used for initialization and
          873 it is not retained.
          874 
          875 CLASS-AND-TYPE is either a list of the form (class-name
          876 struct-type) or a single symbol naming both.  The class will
          877 inherit SUPERS.  If a list of SLOTS is specified, only those
          878 slots will be defined and stored."
          879   (destructuring-bind (class-name &optional (struct-type (list :struct class-name)))
          880       (ensure-list class-and-type)
          881     (let ((slots (or slots (foreign-slot-names struct-type))))
          882       `(progn
          883          (defclass ,class-name ,supers
          884            ,(loop for slot in slots collect
          885                   `(,slot :reader ,(format-symbol t "~A-~A" class-name slot))))
          886          ;; This could be done in a parent class by using
          887          ;; FOREIGN-SLOT-NAMES when instantiating but then the compiler
          888          ;; macros wouldn't kick in.
          889          (defmethod initialize-instance :after ((inst ,class-name) &key pointer)
          890            (with-foreign-slots (,slots pointer ,struct-type)
          891              ,@(loop for slot in slots collect
          892                      `(setf (slot-value inst ',slot) ,slot))))
          893          ',class-name))))
          894 
          895 ;;;# Foreign Unions
          896 ;;;
          897 ;;; A union is a subclass of FOREIGN-STRUCT-TYPE in which all slots
          898 ;;; have an offset of zero.
          899 
          900 ;;; See also the notes regarding ABI requirements in
          901 ;;; NOTICE-FOREIGN-STRUCT-DEFINITION
          902 (defun notice-foreign-union-definition (name-and-options slots)
          903   "Parse and install a foreign union definition."
          904   (destructuring-bind (name &key size)
          905       (ensure-list name-and-options)
          906     (let ((union (make-instance 'foreign-union-type :name name))
          907           (max-size 0)
          908           (max-align 0))
          909       (with-tentative-type-definition (name union :union)
          910         (dolist (slotdef slots)
          911           (destructuring-bind (slotname type &key (count 1)) slotdef
          912             (when (eq (canonicalize-foreign-type type) :void)
          913               (simple-foreign-type-error name :struct
          914                                          "In union ~S: void type not allowed in field ~S"
          915                                          name slotdef))
          916             (let* ((slot (make-struct-slot slotname 0 type count))
          917                    (size (* count (foreign-type-size type)))
          918                    (align (foreign-type-alignment (slot-type slot))))
          919               (setf (gethash slotname (slots union)) slot)
          920               (when (> size max-size)
          921                 (setf max-size size))
          922               (when (> align max-align)
          923                 (setf max-align align)))))
          924         (setf (size union) (or size max-size))
          925         (setf (alignment union) max-align)))))
          926 
          927 (define-parse-method :union (name)
          928   (funcall (find-type-parser name :union)))
          929 
          930 (defmacro defcunion (name-and-options &body fields)
          931   "Define the layout of a foreign union."
          932   (discard-docstring fields)
          933   (destructuring-bind (name &key size)
          934       (ensure-list name-and-options)
          935     (declare (ignore size))
          936     `(eval-when (:compile-toplevel :load-toplevel :execute)
          937        (notice-foreign-union-definition ',name-and-options ',fields)
          938        (define-parse-method ,name ()
          939          (parse-deprecated-struct-type ',name :union))
          940        '(:union ,name))))
          941 
          942 ;;;# Operations on Types
          943 
          944 (defmethod foreign-type-alignment (type)
          945   "Return the alignment in bytes of a foreign type."
          946   (foreign-type-alignment (parse-type type)))
          947 
          948 (defmacro with-foreign-object ((var type &optional (count 1)) &body body)
          949   "Bind VAR to a pointer to COUNT objects of TYPE during BODY.
          950 The buffer has dynamic extent and may be stack allocated."
          951   `(with-foreign-pointer
          952        (,var ,(if (constantp type)
          953                   ;; with-foreign-pointer may benefit from constant folding:
          954                   (if (constantp count)
          955                       (* (eval count) (foreign-type-size (eval type)))
          956                       `(* ,count ,(foreign-type-size (eval type))))
          957                   `(* ,count (foreign-type-size ,type))))
          958      ,@body))
          959 
          960 (defmacro with-foreign-objects (bindings &body body)
          961   (if bindings
          962       `(with-foreign-object ,(car bindings)
          963          (with-foreign-objects ,(cdr bindings)
          964            ,@body))
          965       `(progn ,@body)))
          966 
          967 ;;;## Anonymous Type Translators
          968 ;;;
          969 ;;; (:wrapper :to-c some-function :from-c another-function)
          970 ;;;
          971 ;;; TODO: We will need to add a FREE function to this as well I think.
          972 ;;; --james
          973 
          974 (define-foreign-type foreign-type-wrapper ()
          975   ((to-c   :initarg :to-c   :reader wrapper-to-c)
          976    (from-c :initarg :from-c :reader wrapper-from-c))
          977   (:documentation "Wrapper type."))
          978 
          979 (define-parse-method :wrapper (base-type &key to-c from-c)
          980   (make-instance 'foreign-type-wrapper
          981                  :actual-type (parse-type base-type)
          982                  :to-c (or to-c 'identity)
          983                  :from-c (or from-c 'identity)))
          984 
          985 (defmethod translate-to-foreign (value (type foreign-type-wrapper))
          986   (translate-to-foreign
          987    (funcall (slot-value type 'to-c) value) (actual-type type)))
          988 
          989 (defmethod translate-from-foreign (value (type foreign-type-wrapper))
          990   (funcall (slot-value type 'from-c)
          991            (translate-from-foreign value (actual-type type))))
          992 
          993 ;;;# Other types
          994 
          995 ;;; Boolean type. Maps to an :int by default. Only accepts integer types.
          996 (define-foreign-type foreign-boolean-type ()
          997   ())
          998 
          999 (define-parse-method :boolean (&optional (base-type :int))
         1000   (make-instance
         1001    'foreign-boolean-type :actual-type
         1002    (ecase (canonicalize-foreign-type base-type)
         1003      ((:char :unsigned-char :int :unsigned-int :long :unsigned-long
         1004        #-cffi-sys::no-long-long :long-long
         1005        #-cffi-sys::no-long-long :unsigned-long-long) base-type))))
         1006 
         1007 (defmethod translate-to-foreign (value (type foreign-boolean-type))
         1008   (if value 1 0))
         1009 
         1010 (defmethod translate-from-foreign (value (type foreign-boolean-type))
         1011   (not (zerop value)))
         1012 
         1013 (defmethod expand-to-foreign (value (type foreign-boolean-type))
         1014   "Optimization for the :boolean type."
         1015   (if (constantp value)
         1016       (if (eval value) 1 0)
         1017       `(if ,value 1 0)))
         1018 
         1019 (defmethod expand-from-foreign (value (type foreign-boolean-type))
         1020   "Optimization for the :boolean type."
         1021   (if (constantp value) ; very unlikely, heh
         1022       (not (zerop (eval value)))
         1023       `(not (zerop ,value))))
         1024 
         1025 ;;; Boolean type that represents C99 _Bool
         1026 (defctype :bool (:boolean :char))
         1027 
         1028 ;;;# Typedefs for built-in types.
         1029 
         1030 (defctype :uchar  :unsigned-char)
         1031 (defctype :ushort :unsigned-short)
         1032 (defctype :uint   :unsigned-int)
         1033 (defctype :ulong  :unsigned-long)
         1034 (defctype :llong  :long-long)
         1035 (defctype :ullong :unsigned-long-long)
         1036 
         1037 ;;; We try to define the :[u]int{8,16,32,64} types by looking at
         1038 ;;; the sizes of the built-in integer types and defining typedefs.
         1039 (eval-when (:compile-toplevel :load-toplevel :execute)
         1040   (macrolet
         1041       ((match-types (sized-types mtypes)
         1042          `(progn
         1043             ,@(loop for (type . size-or-type) in sized-types
         1044                     for m = (car (member (if (keywordp size-or-type)
         1045                                              (foreign-type-size size-or-type)
         1046                                              size-or-type)
         1047                                          mtypes :key #'foreign-type-size))
         1048                     when m collect `(defctype ,type ,m)))))
         1049     ;; signed
         1050     (match-types ((:int8 . 1) (:int16 . 2) (:int32 . 4) (:int64 . 8)
         1051                   (:intptr . :pointer))
         1052                  (:char :short :int :long :long-long))
         1053     ;; unsigned
         1054     (match-types ((:uint8 . 1) (:uint16 . 2) (:uint32 . 4) (:uint64 . 8)
         1055                   (:uintptr . :pointer))
         1056                  (:unsigned-char :unsigned-short :unsigned-int :unsigned-long
         1057                   :unsigned-long-long))))