Problems with nested structs and the newer cffi

Willem Rein Oudshoorn woudshoo at xs4all.nl
Sat Apr 20 08:40:17 UTC 2013


I am encountering some problems with trying to upgrade my old cffi code
to the new version from quicklisp.  
If I use the old code, I get lots of warnings about my structs, that I
should use either (:struct ...) or (:pointer (:struct ...))

However whateer I try, I do not seem to get it to work, and I am
starting to think there is some issue between me and the new cffi.


The main issue is a nested struct definition like this:

```
(defcstruct timeval
  (time %time)
  (offset :int))

(defcstruct (git-signature)
  (name :string)
  (email :string)
  (time (:struct timeval)))
```

With type definitions

```
(define-foreign-type time-type ()
  nil
  (:actual-type :int64)
  (:simple-parser %time))

(define-foreign-type git-signature-type ()
  nil
  (:actual-type :pointer)
  (:simple-parser %git-signature))
```

I encounter problems when I am trying to update the 
`translate-to-foreign` for the `git-signature-type`.
The implementation boils down to:

```
(defmethod translate-to-foreign ((value list) (type git-signature-type))
  (let ((signature (foreign-alloc '(:struct git-signature))))
    (with-foreign-slots ((name email time) signature (:struct git-signature))
      (setf name (getf value :name (getenv "USER")))
      (setf email (getf value :email (default-email)))
      (with-foreign-slots ((time offset) time (:struct timeval))
        (let ((time-to-set (getf value :time (local-time:now))))
          (setf time time-to-set)
          (setf offset (/ (local-time:timestamp-subtimezone
                           time-to-set local-time:*default-timezone*)
                          60)))))
    signature)
```

The problem is in the inner `with-foreign-slots ((time offset)...`.

The error I get is:

; Evaluation aborted on #<TYPE-ERROR expected-type: SYSTEM-AREA-POINTER
             datum: (CL-GIT::OFFSET 0 TIME @1970-01-01T01:00:03.000000+01:00)>.


The reason is, as far as I can tell, that in the code:

    (with-foreign-slots ((time offset) time (:struct timeval)) ...

the value of `time` is already a plist (due to the outer
with-foreign-slots), and the inner with-foreign-slots expects a pointer.

So what is the best way of fixing this?  I can fix this by replacing
the inner `with-foreign-slots` by

```
      (with-foreign-slots ((time offset) 
			   (foreign-slot-pointer signature '(:struct git-signature) 'time) 
			   (:struct timeval))
```
which seems a bit long.


An additional question is, when to use (:struct ...) and when to use 
(:pointer (:struct ..)))

I did expect that I needed to use (:pointer (:struct ..)) 
in the toplevel `with-foreign-slots`, because the argument is actually
a pointer to the struct.  But that did not work.


As you can tell, I am a bit confused.  
Hope that someone can give some hints to clear my head.

Kind regards,
Wim Oudshoorn.




More information about the cffi-devel mailing list