ffi.scm 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. ;; Author: Maxime Devos
  2. (define-module (mach ffi)
  3. #:export (define-bitfield define-ffi wrap-bits unwrap-bits
  4. ffi:pointer ffi:unsigned-int ffi:off_t ffi:int
  5. ffi:bool bool->ffi-int define-ffi-enum
  6. with-foreign-variable with-foreign-variables*)
  7. #:re-export (pointer-address null-pointer? define-wrapped-pointer-type
  8. make-pointer make-c-struct dereference-pointer %null-pointer)
  9. #:use-module (system foreign)
  10. #:use-module (rnrs bytevectors)
  11. #:use-module (ice-9 receive))
  12. (define ffi:int int)
  13. (define ffi:bool ffi:int) ;; XXX
  14. ;; XXX check
  15. (define (bool->ffi-int bool)
  16. (if bool 1 0))
  17. (define ffi:pointer '*)
  18. (define ffi:unsigned-int unsigned-int)
  19. (define ffi:off_t unsigned-int) ;; XXX verify
  20. ;; TODO: check whethe VALUE ... are disjoint.
  21. ;; TODO: it would be nice if separate bitfield types were disjoint.
  22. (define-syntax-rule (define-bitfield bitfield-name (name value) ...)
  23. (begin (define name value) ...))
  24. (define-syntax-rule (wrap-bits bitfield)
  25. (lambda (x) x))
  26. (define-syntax-rule (unwrap-bits bitfield)
  27. (lambda (x) x))
  28. (define-syntax-rule (define-ffi (cname name) (return wrap) (arg type unwrap) ...)
  29. "Define a binding NAME to the C function NAME, lowering each argument ARG
  30. using UNWRAP to the C representation TYPE, and wrapping the return value
  31. of type RETURN with WRAP. Resolving is delayed, to aid development on
  32. GNU/Linux and cross-compilation."
  33. (define name
  34. (let ((c (delay (pointer->procedure return
  35. (dynamic-func cname (dynamic-link))
  36. (list type ...)
  37. #:return-errno? #t))))
  38. (lambda (arg ...)
  39. (receive (result errno)
  40. (apply (force c) (unwrap arg) ...)
  41. (values (wrap result) errno))))))
  42. ;; TODO: check whether VALUE ... are disjoint.
  43. ;; TODO: it would be nice if separate bitfield types were disjoint.
  44. ;;
  45. ;; ffi:base: underlying C type (ffi:int, ffi:unsigned-int, ...)
  46. (define-syntax-rule (define-ffi-enum (ffi:name ffi:base) (%wrap-enum %unwrap-enum) (name value) ...)
  47. (begin (define ffi:name ffi:base)
  48. (define name value) ...
  49. (define (%wrap-enum x) x)
  50. (define (%unwrap-enum x) x)))
  51. (define-syntax with-foreign-variable
  52. (lambda (s)
  53. "Allocate a region of foreign memory for holding a @code{ffi:type}.
  54. Bind @var{box} to this region of foreign memory, such that it can be
  55. referenced (yielding a @code{ffi:type}) and @code{set!} as an ordinary
  56. Scheme variable. Its initial value is @var{init}.
  57. @var{box} is also available as a pointer @var{%box}."
  58. (syntax-case s ()
  59. ((_ (box %box ffi:type init) exp exp* ...)
  60. (not (free-identifier=? #'box #'%box))
  61. #'(let* ((type ffi:type)
  62. (%box (make-c-struct (list type) (list init))))
  63. (let-syntax ((box (make-variable-transformer
  64. (lambda (x)
  65. (syntax-case x ()
  66. (var (identifier? #'var)
  67. #'(%dereference %box type))
  68. ;; XXX can we assume set == set!
  69. ;; and var == box here?
  70. ((set var value)
  71. #'(%assign! %box type value)))))))
  72. exp exp* ...))))))
  73. (define-syntax with-foreign-variables*
  74. (syntax-rules ()
  75. ((_ () . exps) (let () . exps))
  76. ((_ (binding . rest) . exps)
  77. (with-foreign-variable binding
  78. (with-foreign-variables* rest . exps)))))
  79. ;; TODO: ideally, these two wouldn't require any memory allocations ...
  80. (define (%dereference %box type)
  81. (car (parse-c-struct %box (list type))))
  82. (define (%assign! %box type value)
  83. (let ((%value (make-c-struct (list type) (list value)))
  84. (size (sizeof type)))
  85. (bytevector-copy! (pointer->bytevector %value size) 0
  86. (pointer->bytevector %box size) 0
  87. size)))