Commit 110c1a93 authored by Kenny Tilton's avatar Kenny Tilton
Browse files

Moving Hello-c (my UFFI fork) to its own module (under Cello)

parents
Loading
Loading
Loading
Loading

.gitignore

0 → 100644
+28 −0
Original line number Diff line number Diff line
# CVS default ignores begin
tags
TAGS
.make.state
.nse_depinfo
*~
#*
.#*
,*
_$*
*$
*.old
*.bak
*.BAK
*.orig
*.rej
.del-*
*.a
*.olb
*.o
*.obj
*.so
*.exe
*.Z
*.elc
*.ln
core
# CVS default ignores end

aggregates.lisp

0 → 100644
+252 −0
Original line number Diff line number Diff line
;;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; Base: 10; Package: hic -*-
;;;; *************************************************************************
;;;; FILE IDENTIFICATION
;;;;
;;;; Name:          aggregates.lisp
;;;; Purpose:       hic source to handle aggregate types
;;;; Programmer:    Kevin M. Rosenberg
;;;; Date Started:  Feb 2002
;;;;
;;;; $Id: aggregates.lisp,v 1.1 2004/12/14 03:58:48 ktilton Exp $
;;;;
;;;; This file, part of hic, is Copyright (c) 2002 by Kevin M. Rosenberg
;;;;
;;;; hic users are granted the rights to distribute and use this software
;;;; as governed by the terms of the Lisp Lesser GNU Public License
;;;; (http://opensource.franz.com/preamble.html), also known as the LLGPL.
;;;; *************************************************************************

(in-package #:hic)

(defmacro def-enum (enum-name args &key (separator-string "#"))
  "Creates a constants for a C type enum list, symbols are created
in the created in the current package. The symbol is the concatenation
of the enum-name name, separator-string, and field-name"
  (let ((counter 0)
	(cmds nil)
	(constants nil))
    (declare (fixnum counter))
    (dolist (arg args)
      (let ((name (if (listp arg) (car arg) arg))
	    (value (if (listp arg) 
		       (prog1
			   (setq counter (cadr arg))
			 (incf counter))
		     (prog1 
			 counter
		       (incf counter)))))
	(setq name (intern (concatenate 'string
			     (symbol-name enum-name)
			     separator-string
			     (symbol-name name))))
	(push `(ffx:def-constant ,name ,value) constants)))
    (setf cmds (append '(progn)
		       #+allegro `((ff:def-foreign-type ,enum-name :int))
		       #+lispworks `((fli:define-c-typedef ,enum-name :int))
		       #+(or cmu scl) `((alien:def-alien-type ,enum-name alien:signed))
		       #+sbcl `((sb-alien:define-alien-type ,enum-name sb-alien:signed))
                       #+(and mcl (not openmcl)) `((def-mcl-type ,enum-name :integer))
                       #+openmcl `((ccl::def-foreign-type ,enum-name :int))
		       (nreverse constants)))
    cmds))


(defmacro def-array-pointer (name-array type)
  #+allegro
  `(ff:def-foreign-type ,name-array 
    (:array ,(convert-from-uffi-type type :array)))
  #+lispworks
  `(fli:define-c-typedef ,name-array
    (:c-array ,(convert-from-uffi-type type :array)))
  #+(or cmu scl)
  `(alien:def-alien-type ,name-array 
    (* ,(convert-from-uffi-type type :array)))
  #+sbcl
  `(sb-alien:define-alien-type ,name-array 
    (* ,(convert-from-uffi-type type :array)))
  #+(and mcl (not openmcl))
  `(def-mcl-type ,name-array '(:array ,type))
  #+openmcl
  `(ccl::def-foreign-type ,name-array (:array ,(convert-from-uffi-type type :array)))
  )

(defun process-struct-fields (name fields &optional (variant nil))
  (let (processed)
    (dolist (field fields)
      (let* ((field-name (car field))
	     (type (cadr field))
	     (def (append (list field-name)
			  (if (eq type :pointer-self)
			      #+(or cmu scl) `((* (alien:struct ,name)))
			      #+sbcl `((* (sb-alien:struct ,name)))
			      #+mcl `((:* (:struct ,name)))
			      #+lispworks `((:pointer ,name))
			      #-(or cmu sbcl scl mcl lispworks) `((* ,name))
			      `(,(convert-from-uffi-type type :struct))))))
	(if variant
	    (push (list def) processed)
	  (push def processed))))
    (nreverse processed)))
	    
(defmacro def-struct (name &rest fields)
  #+(or cmu scl)
  `(alien:def-alien-type ,name (alien:struct ,name ,@(process-struct-fields name fields)))
  #+sbcl
  `(sb-alien:define-alien-type ,name (sb-alien:struct ,name ,@(process-struct-fields name fields)))
  #+allegro
  `(ff:def-foreign-type ,name (:struct ,@(process-struct-fields name fields)))
  #+lispworks
  `(fli:define-c-struct ,name ,@(process-struct-fields name fields))
  #+(and mcl (not openmcl))
  `(ccl:defrecord ,name ,@(process-struct-fields name fields))
  #+openmcl
  `(ccl::def-foreign-type
    nil 
    (:struct ,name ,@(process-struct-fields name fields)))
  )


(defmacro get-slot-value (obj type slot)
  #+(or lispworks cmu sbcl scl) (declare (ignore type))
  #+allegro
  `(ff:fslot-value-typed ,type :c ,obj ,slot)
  #+lispworks
  `(fli:foreign-slot-value ,obj ,slot)
  #+(or cmu scl)
  `(alien:slot ,obj ,slot)
  #+sbcl
  `(sb-alien:slot ,obj ,slot)
  #+mcl
  `(ccl:pref ,obj ,(read-from-string (format nil ":~a.~a" (keyword type) (keyword slot))))
  )

#+mcl
(defmacro set-slot-value (obj type slot value) ;use setf to set values
  `(setf (ccl:pref ,obj ,(read-from-string (format nil ":~a.~a" (keyword type) (keyword slot)))) ,value))

#+mcl
(defsetf get-slot-value set-slot-value)


(defmacro get-slot-pointer (obj type slot)
  #+(or lispworks cmu sbcl scl) (declare (ignore type))
  #+allegro
  `(ff:fslot-value-typed ,type :c ,obj ,slot)
  #+lispworks
  `(fli:foreign-slot-pointer ,obj ,slot)
  #+(or cmu scl)
  `(alien:slot ,obj ,slot)
  #+sbcl
  `(sb-alien:slot ,obj ,slot)
  #+(and mcl (not openmcl))
  `(ccl:%int-to-ptr (+ (ccl:%ptr-to-int ,obj) (the fixnum (ccl:field-info ,type ,slot))))
  #+openmcl
  `(let ((field (ccl::%find-foreign-record-type-field ,type ,slot)))
     (ccl:%int-to-ptr (+ (ccl:%ptr-to-int ,obj) (the fixnum (ccl::foreign-record-field-offset field)))))  
)

;; necessary to eval at compile time for openmcl to compile convert-from-foreign-usb8
;; below
(eval-when (:compile-toplevel :load-toplevel :execute)
  ;; so we could allow '(:array :long) or deref with other type like :long only
  #+mcl
  (defun array-type (type)
    (let ((result type))
      (when (listp type)
	(let ((type-list (if (eq (car type) 'quote) (nth 1 type) type)))
	  (when (and (listp type-list) (eq (car type-list) :array))
	    (setf result (cadr type-list)))))
      result))
  
  
  (defmacro deref-array (obj type i)
    "Returns a field from a row"
    #+(or lispworks cmu sbcl scl) (declare (ignore type))
    #+(or cmu scl)  `(alien:deref ,obj ,i)
    #+sbcl `(sb-alien:deref ,obj ,i)
    #+lispworks `(fli:dereference ,obj :index ,i :copy-foreign-object nil)
    #+allegro `(ff:fslot-value-typed (quote ,(convert-from-uffi-type type :type)) :c ,obj ,i)
    #+openmcl
    (let* ((array-type (array-type type))
	   (local-type (convert-from-uffi-type array-type :allocation))
	   (element-size-in-bits (ccl::%foreign-type-or-record-size local-type :bits)))
      (ccl::%foreign-access-form
       obj
       (ccl::%foreign-type-or-record local-type)
       `(* ,i ,element-size-in-bits)
       nil))
    #+(and mcl (not openmcl))
    (let* ((array-type (array-type type))
	   (local-type (convert-from-uffi-type array-type :allocation))
	   (accessor (first (macroexpand `(ccl:pref obj ,local-type)))))
      `(,accessor
	,obj
	(* (the fixnum ,i) ,(size-of-foreign-type local-type))))
    ))
  
; this expands to the %set-xx functions which has different params than %put-xx
#+(and mcl (not openmcl))
(defmacro deref-array-set (obj type i value)
  (let* ((array-type (array-type type))
         (local-type (convert-from-uffi-type array-type :allocation))
         (accessor (first (macroexpand `(ccl:pref obj ,local-type))))
         (settor (first (macroexpand `(setf (,accessor obj ,local-type) value)))))
    `(,settor 
      ,obj
      (* (the fixnum ,i) ,(size-of-foreign-type local-type)) 
      ,value)))

#+(and mcl (not openmcl))
(defsetf deref-array deref-array-set)

(defmacro def-union (name &rest fields)
  #+allegro
  `(ff:def-foreign-type ,name (:union ,@(process-struct-fields name fields)))
  #+lispworks
  `(fli:define-c-union ,name ,@(process-struct-fields name fields))
  #+(or cmu scl)
  `(alien:def-alien-type ,name (alien:union ,name ,@(process-struct-fields name fields)))
  #+sbcl
  `(sb-alien:define-alien-type ,name (sb-alien:union ,name ,@(process-struct-fields name fields)))
  #+(and mcl (not openmcl))
  `(ccl:defrecord ,name (:variant ,@(process-struct-fields name fields t)))
  #+openmcl
  `(ccl::def-foreign-type nil 
			  (:union ,name ,@(process-struct-fields name fields)))
)


#-(or sbcl cmu)
(defun convert-from-foreign-usb8 (s len)
  (declare (optimize (speed 3) (space 0) (safety 0) (compilation-speed 0))
	   (fixnum len))
  (let ((a (make-array len :element-type '(unsigned-byte 8))))
    (dotimes (i len a)
      (declare (fixnum i))
      (setf (aref a i) (uffi:deref-array s '(:array :unsigned-byte) i)))))

#+sbcl
(defun convert-from-foreign-usb8 (s len)
  (let ((sap (sb-alien:alien-sap s)))
    (declare (type sb-sys:system-area-pointer sap))
    (locally
	(declare (optimize (speed 3) (safety 0)))
      (let ((result (make-array len :element-type '(unsigned-byte 8))))
	(sb-kernel:copy-from-system-area sap 0
					 result (* sb-vm:vector-data-offset
						   sb-vm:n-word-bits)
					 (* len sb-vm:n-byte-bits))
	result))))

#+cmu
(defun convert-from-foreign-usb8 (s len)
  (let ((sap (alien:alien-sap s)))
    (declare (type system:system-area-pointer sap))
    (locally
	(declare (optimize (speed 3) (safety 0)))
      (let ((result (make-array len :element-type '(unsigned-byte 8))))
	(kernel:copy-from-system-area sap 0
				      result (* vm:vector-data-offset
						vm:word-bits)
				      (* len vm:byte-bits))
	result))))

arrays.lisp

0 → 100644
+196 −0
Original line number Diff line number Diff line
;; -*- mode: Lisp; Syntax: Common-Lisp; Package: hello-c; -*-
;;;
;;; Copyright  1995,2003 by Kenneth William Tilton.
;;;
;;; Permission is hereby granted, free of charge, to any person obtaining a copy 
;;; of this software and associated documentation files (the "Software"), to deal 
;;; in the Software without restriction, including without limitation the rights 
;;; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
;;; copies of the Software, and to permit persons to whom the Software is furnished 
;;; to do so, subject to the following conditions:
;;;
;;; The above copyright notice and this permission notice shall be included in 
;;; all copies or substantial portions of the Software.
;;;
;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
;;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
;;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
;;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
;;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
;;; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 
;;; IN THE SOFTWARE.



  
(in-package :hello-c)
  
(defparameter *gl-rsrc* nil)

(defparameter *fgn-mem* nil)

(defun fgn-dump ()
  (print (length *fgn-mem*))
  (loop for fgn in *fgn-mem*
        do (print fgn)
        summing (fgn-amt fgn)))

#+check
(fgn-dump)

(defun ffx-reset (&optional force)
  (hic-reset force))

(defun hic-reset (&optional force)
  (if force
      (progn
        (loop for fgn in *fgn-mem*
            do (print fgn)
              (fgn-free (fgn-ptr fgn))
            finally (setf *fgn-mem* nil))
        (loop for fgn in *gl-rsrc*
            do (print fgn)
              (glfree (fgn-type fgn)(fgn-ptr fgn))
            finally (setf *gl-rsrc* nil))
    (progn
      (when *fgn-mem*
        (loop for fgn in *fgn-mem*
            do (print fgn)
            finally (break "above fgn-mem not freed")))
      (when *gl-rsrc*
        (loop for fgn in *gl-rsrc*
            do (print fgn)
            finally (break "above *gl-rsrc* not freed")))))))

(defstruct fgn ptr id type amt)

(defmethod print-object ((fgn fgn) s)
  (format s "fgnmem ~a :amt ~a :type ~a"
    (fgn-id fgn)(fgn-amt fgn)(fgn-type fgn)))

(defmacro fgn-alloc (type amt-form &rest keys)
  (let ((amt (gensym))
        (ptr (gensym)))
    `(let* ((,amt ,amt-form)
            (,ptr (allocate-foreign-object ,type ,amt)))
       (call-fgn-alloc ,type ,amt ,ptr (list ,@keys)))))

(defun call-fgn-alloc (type amt ptr keys)
  ;;(print `(fgnalloc ,type ,amt ,keys))
  (fgn-ptr (car (push (make-fgn :id keys
                        :type type
                        :amt amt
                        :ptr ptr)
                  *fgn-mem*))))

(defun fgn-free (&rest fgn-ptrs)
  (loop for fgn-ptr in fgn-ptrs do
        (let ((fgn (find fgn-ptr *fgn-mem* :key 'fgn-ptr)))
          (if fgn
              (setf *fgn-mem* (delete fgn *fgn-mem*))
            (format t "~&Freeing unknown FGN ~a" fgn-ptr))
          (free-foreign-object fgn-ptr))))

(defun gllog (type resource amt &rest keys)
  (push (make-fgn :id keys
          :type type
          :amt amt
          :ptr resource)
    *gl-rsrc*))

(defun glfree (type resource)
  (let ((fgn (find (cons type resource) *gl-rsrc*
               :test 'equal
               :key (lambda (g)
                      (cons (fgn-type g)(fgn-ptr g))))))
    (if fgn
        (setf *gl-rsrc* (delete fgn *gl-rsrc*))
      (format t "~&Freeing unknown GL resource ~a" (cons type resource)))
    #+nonono (ecase type
      (:texture (ogl:ogl-texture-delete resource)))))

(defmacro make-ff-array (type &rest values)
  (let ((fv (gensym))(n (gensym))(vs (gensym)))
    `(let ((,fv (fgn-alloc ',type ,(length values) :make-ff-array))
           (,vs (list ,@values)))
       (dotimes (,n ,(length values) ,fv)
         (setf (ff-elt ,fv ,type ,n)
           (coerce (nth ,n ,vs) ',(if (keywordp type)
                                     (intern (symbol-name type))
                                   (get type 'ffi-cast))))))))

(defmacro ff-list (array type count)
  (let ((a (gensym))(n (gensym)))
  `(loop with ,a = ,array
       for ,n below ,count
       collecting (ff-elt ,a ,type ,n))))

(defun make-floatv (&rest floats)
  (let* ((co (fgn-alloc :float (length floats) :make-floatv))
         )
    (apply 'ff-floatv-setf co floats)))

(defmacro ff-floatv-ensure (place &rest values)
  `(if ,place
       (ff-floatv-setf ,place ,@values)
     (setf ,place (make-floatv ,@values))))

(defun ff-floatv-setf (array &rest floats)
  (loop for f in floats
        and n upfrom 0
        do (setf (deref-array array '(:array :float) n) (* 1.0 f)))
  array)

;--------- with-ff-array-elements ------------------------------------------


(defmacro with-ff-array-elements ((fa type &rest refs) &body body)
  `(let ,(let ((refn -1))
           (mapcar (lambda (ref)
                     `(,ref (deref-array ,fa '(:array ,type) ,(incf refn))))
             refs))
     ,@body))

;-------- ff-elt ---------------------------------------

(defmacro ff-elt-p (v n)
  `(deref-array ,v '(:array (* :void)) ,n))

(defmacro ff-elt (v type n)
  `(deref-array ,v '(:array ,type) ,n))

(defun elti (v n)
  (ff-elt v :int n))

(defun (setf elti) (value v n)
  (setf (ff-elt v :int n) (coerce value 'integer)))

(defun eltf (v n)
  (ff-elt v :float n))

(defun (setf eltf) (value v n)
  (setf (ff-elt v :float n) (coerce value 'float)))

(defun elt$ (v n)
  (ff-elt v :cstring n))

(defun (setf elt$) (value v n)
  (setf (ff-elt v :cstring n) value))

(defun eltd (v n)
  (ff-elt v :double n))

(defun (setf eltd) (value v n)
  (setf (ff-elt v :double n) (coerce value 'double-float)))

(defmacro fgn-pa (pa n)
  `(deref-array ,pa '(:array (* :void)) ,n))

(eval-when (compile load eval)
  (export '(ffx-reset
           ff-elt ff-list
           eltf eltd elti fgn-pa
           with-ff-array-elements
           make-ff-array
           make-floatv ff-floatv-ensure
           hic-reset fgn-alloc fgn-free gllog glfree)))
 No newline at end of file

callbacks.lisp

0 → 100644
+84 −0
Original line number Diff line number Diff line
;; -*- mode: Lisp; Syntax: Common-Lisp; Package: hello-c; -*-
;;;
;;; Copyright © 1995,2003 by Kenneth William Tilton.
;;;
;;; Permission is hereby granted, free of charge, to any person obtaining a copy 
;;; of this software and associated documentation files (the "Software"), to deal 
;;; in the Software without restriction, including without limitation the rights 
;;; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
;;; copies of the Software, and to permit persons to whom the Software is furnished 
;;; to do so, subject to the following conditions:
;;;
;;; The above copyright notice and this permission notice shall be included in 
;;; all copies or substantial portions of the Software.
;;;
;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
;;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
;;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
;;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
;;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
;;; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 
;;; IN THE SOFTWARE.


(in-package :hello-c)

(defun ff-register-callable (callback-name)
  #+allegro
  (ff:register-foreign-callable callback-name)
  #+lispworks
  (let ((cb (progn ;; fli:pointer-address
              (fli:make-pointer :symbol-name (symbol-name callback-name) ;; leak?
                :functionp t))))
    (print (list :ff-register-callable-returns cb))
    cb))

(defmacro ff-defun-callable (call-convention result-type name args &body body)
  (declare (ignorable result-type))
  (let ((native-args (when args ;; without this p-f-a returns '(:void) as if for declare
                       (process-function-args args))))
    #+lispworks
    `(fli:define-foreign-callable
      (,(symbol-name name) :result-type ,result-type :calling-convention ,call-convention)
      (,@native-args)
      ,@body)
    #+allegro
    `(ff:defun-foreign-callable ,name ,native-args
       (declare (:convention ,(ecase call-convention
                                (:cdecl :c)
                                (:stdcall :stdcall))))
       ,@body)))


#+test
(ff-defun-callable :cdecl :int square ((arg-1 :int)(data (* :void)))
  (list data (* arg-1 arg-1)))

(defmacro ff-def-call ((module iname ename) args)
  #+cormanlisp
  (assert module () "Module (dll name, in fact) required for Corman Lisp")
  #+cormanlisp
  `(ct:defun-dll ,iname ,args
     :return-type :short
     :library-name ,module ;; required according Corman doc
     :entry-name ,ename
     :linkage-type :c) ;; ??

  #+allegro (declare (ignorable module))
  #+allegro
  `(ff:def-foreign-call (,iname ,ename) ,args)
  #+lispworks
  `(fli:define-foreign-function (,iname ,ename)
     ,(mapcar (lambda (arg) (if (listp (cadr arg))
                                (list (car arg) (substitute :pointer '* (cadr arg)))
                              arg))
        args)
     :module ,module
     :result-type :int))


(eval-when (compile load eval)
  (export '(ff-register-callable
            ff-defun-callable
            ff-def-call
            ff-pointer-address)))
 No newline at end of file

definers.lisp

0 → 100644
+136 −0
Original line number Diff line number Diff line
;; -*- mode: Lisp; Syntax: Common-Lisp; Package: hello-c; -*-
;;;
;;; Copyright  1995,2003 by Kenneth William Tilton.
;;;
;;; Permission is hereby granted, free of charge, to any person obtaining a copy 
;;; of this software and associated documentation files (the "Software"), to deal 
;;; in the Software without restriction, including without limitation the rights 
;;; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
;;; copies of the Software, and to permit persons to whom the Software is furnished 
;;; to do so, subject to the following conditions:
;;;
;;; The above copyright notice and this permission notice shall be included in 
;;; all copies or substantial portions of the Software.
;;;
;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
;;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
;;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
;;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
;;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
;;; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 
;;; IN THE SOFTWARE.

;; $Header: /project/cells/cvsroot/cell-cultures/hello-c/definers.lisp,v 1.1 2004/12/14 03:58:48 ktilton Exp $

(in-package :hello-c)

(eval-when (compile load eval)
  (export '(   
            defun-ffx defun-ffx-multi
               dffr
             dfc
             dft
             dfenum
             make-ff-pointer
             ff-pointer-address
             )))

(defun ff-pointer-address (ff-ptr)
  #-lispworks ff-ptr
  #+lispworks (fli:pointer-address ff-ptr))

(defun make-ff-pointer (n)
  #-lispworks
  n
  #+lispworks
  (fli:make-pointer :address n :pointer-type '(:pointer :void)))

(defmacro defun-ffx (rtn module$ name$ (&rest type-args) &body post-processing)
  (let* ((lisp-fn (lisp-fn name$))
         (lispfn (intern (string-upcase name$)))
         (var-types (let (args)
                      (assert (evenp (length type-args)) () "uneven arg-list for ~a" name$)
                      (dotimes (n (floor (length type-args) 2) (nreverse args))
                        (let ((type (elt type-args (* 2 n)))
                              (var (elt type-args (1+ (* 2 n)))))
                          (when (eql #\* (elt (symbol-name var) 0))
                            ;; no, good with *: (setf var (intern (subseq (symbol-name var) 1)))
                            (setf type `(* ,type)))
                          (push (list var type) args)))))
         (cast-vars (mapcar (lambda (var-type)
                             (copy-symbol (car var-type))) var-types)))
    `(progn
       (def-function (,name$ ,lispfn) ,var-types
         :returning ,rtn
         :module ,module$)
                     
       (defun ,lisp-fn ,(mapcar #'car var-types)
         (let ,(mapcar (lambda (cast-var var-type)
                         `(,cast-var ,(if (listp (cadr var-type))
                                         (car var-type)
                                       (case (cadr var-type)
                                         (:int `(coerce ,(car var-type) 'integer))
                                         (:long `(coerce ,(car var-type) 'integer))
                                         (:unsigned-long `(coerce ,(car var-type) 'integer))
                                         (:unsigned-int `(coerce ,(car var-type) 'integer))
                                         (:float `(coerce ,(car var-type) 'float))
                                         (:double `(coerce ,(car var-type) 'double-float))
                                         (:cstring (car var-type))
                                         (otherwise
                                          (let ((ffc (get (cadr var-type) 'ffi-cast)))
                                            (assert ffc () "Don't know how to cast ~a" (cadr var-type))
                                            `(coerce ,(car var-type) ',ffc)))))))
                 cast-vars var-types)
           (prog1
               (,lispfn ,@cast-vars)
             ,@post-processing)))
       (eval-when (compile eval load)
         (export '(,lispfn ,lisp-fn))))))

(defmacro defun-ffx-multi (rtn module$ &rest name-sig-pairs)
  (assert (evenp (length name-sig-pairs)))
  `(progn
     ,@(loop for name in name-sig-pairs by #'cddr
          and sig in (cdr name-sig-pairs) by #'cddr
          collecting `(defun-ffx ,rtn ,module$ ,name ,sig))))

(defmacro dffr (rtn name$ (&rest type-args))
  `(dff ,rtn ,name$ ,type-args) nil)

(defmacro dfc (sym value)
  `(progn
     (defconstant ,sym ,value)
     (eval-when (compile eval load)
       (export ',sym))))

(defmacro dfenum (remark &rest enum-defs)
  (declare (ignore remark))
  (let ((num -1))
    `(progn
       ,@(loop for edef in enum-defs
            collecting (if (consp edef)
                           `(dfc ,(car edef) ,(setf num (cadr edef)))
                         `(dfc ,edef ,(incf num)))))))

(defmacro dft (ctype ffi-type ffi-cast)
  `(progn
     (setf (get ',ctype 'ffi-cast) ',ffi-cast)
     (def-foreign-type ,ctype ,ffi-type)
     (eval-when (compile eval load)
       (export ',ctype))))

;------ lisp-fn ------------------

(defun lisp-fn (n$)
  (intern
   (with-output-to-string (ln)
    (loop with n$len = (length n$)
        for n upfrom 0
        for c across n$
        when (and (plusp n)
               (upper-case-p c)
               (or (lower-case-p (elt n$ (1- n)))
                 (unless (>= (1+ n) n$len)
                   (lower-case-p (elt n$ (1+ n))))))
        do (princ #\- ln)
        do (princ (char-upcase c) ln)))))
Loading