[cffi-devel] functions that take pointers

Stephen Compall s11 at member.fsf.org
Mon Jan 15 03:11:01 UTC 2007


On Sat, 2007-01-13 at 22:36 -1000, J. T.K. wrote:
> fptr, as an :OUT pointer, is not passed to the function call, but
> status, as an
> :IN-OUT pointer, is passed to ffopen
> 
> The return values are the value of the function,
> and the values pointed to by the pointers fptr and status.
> 
> My question is: Is there any way to make CFFI handle pointers in a
> similar
> manner? How can I do the above in CFFI?

The attached should give you a good general idea of how to do it.  It is
untested.

You can similarly handle out-arguments, but I don't think you can get
away with dropping arguments to the lisp-function without wrapping
defcfun in your package.

You just have to use (in-out :int) etc. as the argtype, and call the
function like:

(call-with-in-out-arguments
 (lambda () (fits-open-file ...))

To do otherwise would change the argument translation semantics, which
currently don't permit argument translators to change the result of
calling a defcfun'd function.  You could add a with-in-outs parametrized
type to use as the rettype in defcfun to get around this, but only as
long as defcfun and foreign-funcall continue to pass the real, complete
call form to expand-type-from-foreign, as is done now.

I used private symbols.  You could do it without private symbols,
probably, but the current exported type translation interface breaks
down when you want to parametrize your own types and have parameters
affect translation.

I'll say here that I don't like the semantics of out and in-out foreign
arguments, and I recommend using a wrapper macro that will more
explicitly handle these results for you.

-- 
Stephen Compall
http://scompall.nocandysw.com/blog
-------------- next part --------------
(defpackage #:s11-cffi
  (:use #:common-lisp #:cffi))

;; private CFFI symbols I need
(eval-when (:compile-toplevel :load-toplevel :execute)
  (import '(cffi::foreign-typedef cffi::define-type-spec-parser
	    cffi::parse-type cffi::unparse cffi::unparse-type
	    cffi::expand-type-to-foreign-dyn)))
;; I also use cffi::name, but decided leaving that fully qualified
;; would reduce confusion.

(in-package #:s11-cffi)

(defclass foreign-in-out-argument (foreign-typedef)
  ((pointee-type :initarg :pointee-type :reader pointee-type))
  (:documentation "TODO"))

(define-type-spec-parser in-out (pointee-type)
  (make-instance 'foreign-in-out-argument
		 :name 'in-out :actual-type (parse-type ':pointer)
		 :pointee-type (parse-type pointee-type)))

(defmethod unparse (name (type foreign-in-out-argument))
  (list name (unparse-type (pointee-type type))))

(defvar .in-out-sink.)
(setf (documentation '.in-out-sink. 'variable)
      "List of in-out output arguments collected by
       call-with-in-out-arguments.")

(defmethod expand-type-to-foreign-dyn
    (value-form var-form body (type foreign-in-out-argument))
  (let ((pointee-type
	  (list 'quote (unparse-type (pointee-type type)))))
    `(with-foreign-object (,var-form ,pointee-type)
       (setf (mem-ref ,var-form ,pointee-type) ,value-form)
       , at body
       (push (mem-ref ,var-form ,pointee-type) .in-out-sink.))))

(defun call-with-in-out-arguments (thunk)
  "Call thunk, collecting any in-out arguments in foreign
functions called therein, appending them in order to the primary
result."
  (let ((.in-out-sink. '()))
    (multiple-value-call #'values
      (values (funcall thunk))
      (values-list .in-out-sink.))))
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 189 bytes
Desc: This is a digitally signed message part
URL: <https://mailman.common-lisp.net/pipermail/cffi-devel/attachments/20070114/ae2ec8e2/attachment.sig>


More information about the cffi-devel mailing list