type-descriptors.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
       ---
       type-descriptors.lisp (4698B)
       ---
            1 ;;;; -*- Mode: lisp; indent-tabs-mode: nil -*-
            2 ;;;
            3 ;;; type-descriptors.lisp --- Build malloc'd libffi type descriptors
            4 ;;;
            5 ;;; Copyright (C) 2009, 2011 Liam M. Healy
            6 ;;;
            7 ;;; Permission is hereby granted, free of charge, to any person
            8 ;;; obtaining a copy of this software and associated documentation
            9 ;;; files (the "Software"), to deal in the Software without
           10 ;;; restriction, including without limitation the rights to use, copy,
           11 ;;; modify, merge, publish, distribute, sublicense, and/or sell copies
           12 ;;; of the Software, and to permit persons to whom the Software is
           13 ;;; furnished to do so, subject to the following conditions:
           14 ;;;
           15 ;;; The above copyright notice and this permission notice shall be
           16 ;;; included in all copies or substantial portions of the Software.
           17 ;;;
           18 ;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
           19 ;;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
           20 ;;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
           21 ;;; NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
           22 ;;; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
           23 ;;; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
           24 ;;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
           25 ;;; DEALINGS IN THE SOFTWARE.
           26 ;;;
           27 
           28 (in-package #:cffi)
           29 
           30 (defmacro type-descriptor-ptr (type)
           31   `(foreign-symbol-pointer ,(format nil "ffi_type_~(~A~)" type)))
           32 
           33 (defmacro type-descriptor-ptr/integer (type)
           34   `(foreign-symbol-pointer
           35     ,(format nil "ffi_type_~Aint~D"
           36              (if (string-equal type "unsigned"
           37                                :end1 (min 8 (length (string type))))
           38                  "u" "s")
           39              (* 8 (foreign-type-size type)))))
           40 
           41 (defun %make-libffi-type-descriptor/struct (type)
           42   (labels
           43       ((slot-multiplicity (slot)
           44          (if (typep slot 'aggregate-struct-slot)
           45              (slot-count slot)
           46              1))
           47        (number-of-items (structure-type)
           48          "Total number of items in the foreign structure."
           49          (loop for val being the hash-value of (structure-slots structure-type)
           50                sum (slot-multiplicity val))))
           51     (let* ((ptr (foreign-alloc '(:struct ffi-type)))
           52            (nitems (number-of-items type))
           53            (type-pointer-array
           54             (foreign-alloc :pointer :count (1+ nitems))))
           55       (loop for slot in (slots-in-order type)
           56             for ltp = (make-libffi-type-descriptor
           57                        (parse-type (slot-type slot)))
           58             with slot-counter = 0
           59             do (if ltp
           60                    (loop
           61                          repeat (slot-multiplicity slot)
           62                          do (setf
           63                              (mem-aref
           64                               type-pointer-array :pointer slot-counter)
           65                              ltp)
           66                          (incf slot-counter))
           67                    (libffi-error nil
           68                                  "Slot type ~A in foreign structure is unknown to libffi."
           69                                  (unparse-type (slot-type slot)))))
           70       (setf (mem-aref type-pointer-array :pointer nitems)
           71             (null-pointer))
           72       (macrolet ((store (slot value)
           73                    `(setf (foreign-slot-value ptr '(:struct ffi-type) ',slot) ,value)))
           74         (store size 0)
           75         (store alignment 0)
           76         (store type +type-struct+)
           77         (store elements type-pointer-array))
           78       ptr)))
           79 
           80 (defgeneric make-libffi-type-descriptor (object)
           81   (:documentation "Build a libffi struct that describes the type for libffi. This will be used as a cached static read-only argument when the actual call happens.")
           82   (:method ((object foreign-built-in-type))
           83     (let ((type-keyword (type-keyword object)))
           84       #.`(case type-keyword
           85            ,@(loop
           86                :for type :in (append *built-in-float-types*
           87                                      *other-builtin-types*)
           88                :collect `(,type (type-descriptor-ptr ,type)))
           89            ,@(loop
           90                :for type :in *built-in-integer-types*
           91                :collect `(,type (type-descriptor-ptr/integer ,type)))
           92            ;; there's a generic error report in an :around method
           93            )))
           94   (:method ((type foreign-pointer-type))
           95     ;; simplify all pointer types into a void*
           96     (type-descriptor-ptr :pointer))
           97   (:method ((type foreign-struct-type))
           98     (%make-libffi-type-descriptor/struct type))
           99   (:method :around (object)
          100     (let ((result (call-next-method)))
          101       (assert result () "~S failed on ~S. That's bad."
          102               'make-libffi-type-descriptor object)
          103       result))
          104   (:method ((type foreign-type-alias))
          105     ;; Set the type pointer on demand for alias types (e.g. typedef, enum, etc)
          106     (make-libffi-type-descriptor (actual-type type))))