cffi-gcl.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 --- cffi-gcl.lisp (10297B) --- 1 ;;;; -*- Mode: lisp; indent-tabs-mode: nil -*- 2 ;;; 3 ;;; cffi-gcl.lisp --- CFFI-SYS implementation for GNU Common Lisp. 4 ;;; 5 ;;; Copyright (C) 2005-2006, Luis Oliveira <loliveira(@)common-lisp.net> 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 ;;; GCL specific notes: 29 ;;; 30 ;;; On ELF systems, a library can be loaded with the help of this: 31 ;;; http://www.copyleft.de/lisp/gcl-elf-loader.html 32 ;;; 33 ;;; Another way is to link the library when creating a new image: 34 ;;; (compiler::link nil "new_image" "" "-lfoo") 35 ;;; 36 ;;; As GCL's FFI is not dynamic, CFFI declarations will only work 37 ;;; after compiled and loaded. 38 39 ;;; *** this port is broken *** 40 ;;; gcl doesn't compile the rest of CFFI anyway.. 41 42 ;;;# Administrivia 43 44 (defpackage #:cffi-sys 45 (:use #:common-lisp #:alexandria) 46 (:export 47 #:canonicalize-symbol-name-case 48 #:pointerp 49 #:%foreign-alloc 50 #:foreign-free 51 #:with-foreign-ptr 52 #:null-ptr 53 #:null-ptr-p 54 #:inc-ptr 55 #:%mem-ref 56 #:%mem-set 57 #:%foreign-funcall 58 #:%foreign-type-alignment 59 #:%foreign-type-size 60 #:%load-foreign-library 61 ;#:make-shareable-byte-vector 62 ;#:with-pointer-to-vector-data 63 #:foreign-var-ptr 64 #:make-callback)) 65 66 (in-package #:cffi-sys) 67 68 ;;;# Mis-*features* 69 (eval-when (:compile-toplevel :load-toplevel :execute) 70 (pushnew :cffi/no-foreign-funcall *features*)) 71 72 ;;; Symbol case. 73 74 (defun canonicalize-symbol-name-case (name) 75 (declare (string name)) 76 (string-upcase name)) 77 78 ;;;# Allocation 79 ;;; 80 ;;; Functions and macros for allocating foreign memory on the stack 81 ;;; and on the heap. The main CFFI package defines macros that wrap 82 ;;; FOREIGN-ALLOC and FOREIGN-FREE in UNWIND-PROTECT for the common 83 ;;; usage when the memory has dynamic extent. 84 85 (defentry %foreign-alloc (int) (int "malloc")) 86 87 ;(defun foreign-alloc (size) 88 ; "Allocate SIZE bytes on the heap and return a pointer." 89 ; (%foreign-alloc size)) 90 91 (defentry foreign-free (int) (void "free")) 92 93 ;(defun foreign-free (ptr) 94 ; "Free a PTR allocated by FOREIGN-ALLOC." 95 ; (%free ptr)) 96 97 (defmacro with-foreign-ptr ((var size &optional size-var) &body body) 98 "Bind VAR to SIZE bytes of foreign memory during BODY. The 99 pointer in VAR is invalid beyond the dynamic extent of BODY, and 100 may be stack-allocated if supported by the implementation. If 101 SIZE-VAR is supplied, it will be bound to SIZE during BODY." 102 (unless size-var 103 (setf size-var (gensym "SIZE"))) 104 `(let* ((,size-var ,size) 105 (,var (foreign-alloc ,size-var))) 106 (unwind-protect 107 (progn ,@body) 108 (foreign-free ,var)))) 109 110 ;;;# Misc. Pointer Operations 111 112 (defun pointerp (ptr) 113 "Return true if PTR is a foreign pointer." 114 (integerp ptr)) 115 116 (defun null-ptr () 117 "Construct and return a null pointer." 118 0) 119 120 (defun null-ptr-p (ptr) 121 "Return true if PTR is a null pointer." 122 (= ptr 0)) 123 124 (defun inc-ptr (ptr offset) 125 "Return a pointer OFFSET bytes past PTR." 126 (+ ptr offset)) 127 128 ;;;# Shareable Vectors 129 ;;; 130 ;;; This interface is very experimental. WITH-POINTER-TO-VECTOR-DATA 131 ;;; should be defined to perform a copy-in/copy-out if the Lisp 132 ;;; implementation can't do this. 133 134 ;(defun make-shareable-byte-vector (size) 135 ; "Create a Lisp vector of SIZE bytes that can passed to 136 ;WITH-POINTER-TO-VECTOR-DATA." 137 ; (make-array size :element-type '(unsigned-byte 8))) 138 139 ;(defmacro with-pointer-to-vector-data ((ptr-var vector) &body body) 140 ; "Bind PTR-VAR to a foreign pointer to the data in VECTOR." 141 ; `(ccl:with-pointer-to-ivector (,ptr-var ,vector) 142 ; ,@body)) 143 144 ;;;# Dereferencing 145 146 (defmacro define-mem-ref/set (type gcl-type &optional c-name) 147 (unless c-name 148 (setq c-name (substitute #\_ #\Space type))) 149 (let ((ref-fn (concatenate 'string "ref_" c-name)) 150 (set-fn (concatenate 'string "set_" c-name))) 151 `(progn 152 ;; ref 153 (defcfun ,(format nil "~A ~A(~A *ptr)" type ref-fn type) 154 0 "return *ptr;") 155 (defentry ,(intern (string-upcase (substitute #\- #\_ ref-fn))) 156 (int) (,gcl-type ,ref-fn)) 157 ;; set 158 (defcfun ,(format nil "void ~A(~A *ptr, ~A value)" set-fn type type) 159 0 "*ptr = value;") 160 (defentry ,(intern (string-upcase (substitute #\- #\_ set-fn))) 161 (int ,gcl-type) (void ,set-fn))))) 162 163 (define-mem-ref/set "char" char) 164 (define-mem-ref/set "unsigned char" char) 165 (define-mem-ref/set "short" int) 166 (define-mem-ref/set "unsigned short" int) 167 (define-mem-ref/set "int" int) 168 (define-mem-ref/set "unsigned int" int) 169 (define-mem-ref/set "long" int) 170 (define-mem-ref/set "unsigned long" int) 171 (define-mem-ref/set "float" float) 172 (define-mem-ref/set "double" double) 173 (define-mem-ref/set "void *" int "ptr") 174 175 (defun %mem-ref (ptr type &optional (offset 0)) 176 "Dereference an object of TYPE at OFFSET bytes from PTR." 177 (unless (zerop offset) 178 (incf ptr offset)) 179 (ecase type 180 (:char (ref-char ptr)) 181 (:unsigned-char (ref-unsigned-char ptr)) 182 (:short (ref-short ptr)) 183 (:unsigned-short (ref-unsigned-short ptr)) 184 (:int (ref-int ptr)) 185 (:unsigned-int (ref-unsigned-int ptr)) 186 (:long (ref-long ptr)) 187 (:unsigned-long (ref-unsigned-long ptr)) 188 (:float (ref-float ptr)) 189 (:double (ref-double ptr)) 190 (:pointer (ref-ptr ptr)))) 191 192 (defun %mem-set (value ptr type &optional (offset 0)) 193 (unless (zerop offset) 194 (incf ptr offset)) 195 (ecase type 196 (:char (set-char ptr value)) 197 (:unsigned-char (set-unsigned-char ptr value)) 198 (:short (set-short ptr value)) 199 (:unsigned-short (set-unsigned-short ptr value)) 200 (:int (set-int ptr value)) 201 (:unsigned-int (set-unsigned-int ptr value)) 202 (:long (set-long ptr value)) 203 (:unsigned-long (set-unsigned-long ptr value)) 204 (:float (set-float ptr value)) 205 (:double (set-double ptr value)) 206 (:pointer (set-ptr ptr value))) 207 value) 208 209 ;;;# Calling Foreign Functions 210 211 ;; TODO: figure out if these type conversions make any sense... 212 (defun convert-foreign-type (type-keyword) 213 "Convert a CFFI type keyword to a GCL type." 214 (ecase type-keyword 215 (:char 'char) 216 (:unsigned-char 'char) 217 (:short 'int) 218 (:unsigned-short 'int) 219 (:int 'int) 220 (:unsigned-int 'int) 221 (:long 'int) 222 (:unsigned-long 'int) 223 (:float 'float) 224 (:double 'double) 225 (:pointer 'int) 226 (:void 'void))) 227 228 (defparameter +cffi-types+ 229 '(:char :unsigned-char :short :unsigned-short :int :unsigned-int 230 :long :unsigned-long :float :double :pointer)) 231 232 (defcfun "int size_of(int type)" 0 233 "switch (type) { 234 case 0: return sizeof(char); 235 case 1: return sizeof(unsigned char); 236 case 2: return sizeof(short); 237 case 3: return sizeof(unsigned short); 238 case 4: return sizeof(int); 239 case 5: return sizeof(unsigned int); 240 case 6: return sizeof(long); 241 case 7: return sizeof(unsigned long); 242 case 8: return sizeof(float); 243 case 9: return sizeof(double); 244 case 10: return sizeof(void *); 245 default: return -1; 246 }") 247 248 (defentry size-of (int) (int "size_of")) 249 250 ;; TODO: all this is doable inside the defcfun; figure that out.. 251 (defun %foreign-type-size (type-keyword) 252 "Return the size in bytes of a foreign type." 253 (size-of (position type-keyword +cffi-types+))) 254 255 (defcfun "int align_of(int type)" 0 256 "switch (type) { 257 case 0: return __alignof__(char); 258 case 1: return __alignof__(unsigned char); 259 case 2: return __alignof__(short); 260 case 3: return __alignof__(unsigned short); 261 case 4: return __alignof__(int); 262 case 5: return __alignof__(unsigned int); 263 case 6: return __alignof__(long); 264 case 7: return __alignof__(unsigned long); 265 case 8: return __alignof__(float); 266 case 9: return __alignof__(double); 267 case 10: return __alignof__(void *); 268 default: return -1; 269 }") 270 271 (defentry align-of (int) (int "align_of")) 272 273 ;; TODO: like %foreign-type-size 274 (defun %foreign-type-alignment (type-keyword) 275 "Return the alignment in bytes of a foreign type." 276 (align-of (position type-keyword +cffi-types+))) 277 278 #+ignore 279 (defun convert-external-name (name) 280 "Add an underscore to NAME if necessary for the ABI." 281 #+darwinppc-target (concatenate 'string "_" name) 282 #-darwinppc-target name) 283 284 (defmacro %foreign-funcall (function-name &rest args) 285 "Perform a foreign function all, document it more later." 286 `(format t "~&;; Calling ~A with args ~S.~%" ,name ',args)) 287 288 (defun defcfun-helper-forms (name rettype args types) 289 "Return 2 values for DEFCFUN. A prelude form and a caller form." 290 (let ((ff-name (intern (format nil "%foreign-function/TildeA:~A" name)))) 291 (values 292 `(defentry ,ff-name ,(mapcar #'convert-foreign-type types) 293 (,(convert-foreign-type rettype) ,name)) 294 `(,ff-name ,@args)))) 295 296 ;;;# Callbacks 297 298 ;;; XXX unimplemented 299 (defmacro make-callback (name rettype arg-names arg-types body-form) 300 0) 301 302 ;;;# Loading Foreign Libraries 303 304 (defun %load-foreign-library (name) 305 "_Won't_ load the foreign library NAME." 306 (declare (ignore name))) 307 308 ;;;# Foreign Globals 309 310 ;;; XXX unimplemented 311 (defmacro foreign-var-ptr (name) 312 "Return a pointer pointing to the foreign symbol NAME." 313 0)