123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899 |
- ;; Author: Maxime Devos
- (define-module (mach ffi)
- #:export (define-bitfield define-ffi wrap-bits unwrap-bits
- ffi:pointer ffi:unsigned-int ffi:off_t ffi:int
- ffi:bool bool->ffi-int define-ffi-enum
- with-foreign-variable with-foreign-variables*)
- #:re-export (pointer-address null-pointer? define-wrapped-pointer-type
- make-pointer make-c-struct dereference-pointer %null-pointer)
- #:use-module (system foreign)
- #:use-module (rnrs bytevectors)
- #:use-module (ice-9 receive))
- (define ffi:int int)
- (define ffi:bool ffi:int) ;; XXX
- ;; XXX check
- (define (bool->ffi-int bool)
- (if bool 1 0))
- (define ffi:pointer '*)
- (define ffi:unsigned-int unsigned-int)
- (define ffi:off_t unsigned-int) ;; XXX verify
- ;; TODO: check whethe VALUE ... are disjoint.
- ;; TODO: it would be nice if separate bitfield types were disjoint.
- (define-syntax-rule (define-bitfield bitfield-name (name value) ...)
- (begin (define name value) ...))
- (define-syntax-rule (wrap-bits bitfield)
- (lambda (x) x))
- (define-syntax-rule (unwrap-bits bitfield)
- (lambda (x) x))
- (define-syntax-rule (define-ffi (cname name) (return wrap) (arg type unwrap) ...)
- "Define a binding NAME to the C function NAME, lowering each argument ARG
- using UNWRAP to the C representation TYPE, and wrapping the return value
- of type RETURN with WRAP. Resolving is delayed, to aid development on
- GNU/Linux and cross-compilation."
- (define name
- (let ((c (delay (pointer->procedure return
- (dynamic-func cname (dynamic-link))
- (list type ...)
- #:return-errno? #t))))
- (lambda (arg ...)
- (receive (result errno)
- (apply (force c) (unwrap arg) ...)
- (values (wrap result) errno))))))
- ;; TODO: check whether VALUE ... are disjoint.
- ;; TODO: it would be nice if separate bitfield types were disjoint.
- ;;
- ;; ffi:base: underlying C type (ffi:int, ffi:unsigned-int, ...)
- (define-syntax-rule (define-ffi-enum (ffi:name ffi:base) (%wrap-enum %unwrap-enum) (name value) ...)
- (begin (define ffi:name ffi:base)
- (define name value) ...
- (define (%wrap-enum x) x)
- (define (%unwrap-enum x) x)))
- (define-syntax with-foreign-variable
- (lambda (s)
- "Allocate a region of foreign memory for holding a @code{ffi:type}.
- Bind @var{box} to this region of foreign memory, such that it can be
- referenced (yielding a @code{ffi:type}) and @code{set!} as an ordinary
- Scheme variable. Its initial value is @var{init}.
- @var{box} is also available as a pointer @var{%box}."
- (syntax-case s ()
- ((_ (box %box ffi:type init) exp exp* ...)
- (not (free-identifier=? #'box #'%box))
- #'(let* ((type ffi:type)
- (%box (make-c-struct (list type) (list init))))
- (let-syntax ((box (make-variable-transformer
- (lambda (x)
- (syntax-case x ()
- (var (identifier? #'var)
- #'(%dereference %box type))
- ;; XXX can we assume set == set!
- ;; and var == box here?
- ((set var value)
- #'(%assign! %box type value)))))))
- exp exp* ...))))))
- (define-syntax with-foreign-variables*
- (syntax-rules ()
- ((_ () . exps) (let () . exps))
- ((_ (binding . rest) . exps)
- (with-foreign-variable binding
- (with-foreign-variables* rest . exps)))))
- ;; TODO: ideally, these two wouldn't require any memory allocations ...
- (define (%dereference %box type)
- (car (parse-c-struct %box (list type))))
- (define (%assign! %box type value)
- (let ((%value (make-c-struct (list type) (list value)))
- (size (sizeof type)))
- (bytevector-copy! (pointer->bytevector %value size) 0
- (pointer->bytevector %box size) 0
- size)))
|