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
(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)
       ,@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.))))

Attachment: signature.asc
Description: This is a digitally signed message part

_______________________________________________
cffi-devel mailing list
cffi-devel@common-lisp.net
http://common-lisp.net/cgi-bin/mailman/listinfo/cffi-devel

Reply via email to