- (unless (null-pointer-p glist)
- ,(when (eq alien-type-spec 'system-area-pointer)
- `(do ((tmp glist (glist-next tmp)))
- ((null-pointer-p tmp))
- ,(cleanup-alien
- element-type-spec `(glist-data tmp ,element-type-spec) t)))
- (glist-free glist)))))
-
-
-
-;;; Array
-#|
-(define-foreign ("g_array_new" %array-new) () garray
- (zero-terminated boolean)
- (clear boolean)
- (element-size unsigned-int))
-
-(defun array-new (&key zero-terminated clear (element-size 4) initial-contents)
- (let ((array (%array-new zero-terminated clear element-size)))
- (when initial-contents
- (dolist (element initial-contents)
- (array-append array element)))
- array))
-
-(define-foreign ("g_array_free" %array-free) () none
- (array garray)
- (free-segment boolean))
-
-(defun array-free (array &optional free-data (free-segment t))
- (when free-data
- (dotimes (i (array-get-size array))
- (free (array-get-pointer array i))))
- (%array-free array free-segment))
-
-(defmacro with-array (binding &body body)
- (let ((array (gensym)))
- (destructuring-bind (var &rest args
- &key (free-contents nil) (free-segment t)
- &allow-other-keys )
- binding
- (remf args :free-contents)
- (remf args :free-segment)
- `(let* ((,array (array-new ,@args))
- (,var (array-get-data ,array)))
- (unwind-protect
- ,@body
- (array-free ,array ,free-contents ,free-segment))))))
-
-;; cl-gtk.c
-(define-foreign ("g_array_insert_int" array-insert-int) () garray
- (array garray)
- (index unsigned-int)
- (value int))
-
-(defun array-insert-value (array index value)
- (etypecase value
- (null (array-insert-int array index 0))
- (integer (array-insert-int array index value))
- (string (array-insert-int array index (sap-int (gforeign::pointer-to-sap (%strdup value)))))
- (pointer (array-insert-int array index (sap-int (gforeign::pointer-to-sap value))))))
-
-(defun array-prepend (array value)
- (array-insert-value array 0 value))
-
-(defun array-append (array value)
- (array-insert-value array (array-get-size array) value))
-
-;; cl-gtk.c
-(define-foreign ("g_array_get_int" array-get-int) () int
- (array garray)
- (index unsigned-int))
-
-(defun array-get-pointer (array index)
- (gforeign::sap-to-pointer (int-sap (array-get-int array index))))
-
-;; cl-gtk.c
-(define-foreign ("g_array_get_data" array-get-data) () pointer
- (array garray))
-
-(define-foreign ("g_array_set_size" array-set-size) () garray
- (array garray)
- (size unsigned-int))
-
-;; cl-gtk.c
-(define-foreign ("g_array_get_size" array-get-size) () int
- (array garray))
-|#
\ No newline at end of file
+ (unwind-protect
+ (map-glist 'list #'identity glist ',element-type)
+ (glist-free glist)))))
+
+(defmethod from-alien-function ((type (eql 'glist)) &rest args)
+ (declare (ignore type))
+ (destructuring-bind (element-type) args
+ #'(lambda (glist)
+ (unwind-protect
+ (map-glist 'list #'identity glist element-type)
+ (glist-free glist)))))
+
+(defmethod cleanup-form (glist (type (eql 'glist)) &rest args)
+ (declare (ignore type args))
+ `(glist-free ,glist))
+
+(defmethod cleanup-function ((type (eql 'glist)) &rest args)
+ (declare (ignore type args))
+ #'glist-free)
+
+
+
+;;;; Single linked list (GSList)
+
+(deftype gslist (type) `(or (null (cons ,type list))))
+
+(defbinding (%gslist-prepend-unsigned "g_slist_prepend") () pointer
+ (gslist pointer)
+ (data unsigned))
+
+(defbinding (%gslist-prepend-signed "g_slist_prepend") () pointer
+ (gslist pointer)
+ (data signed))
+
+(defbinding (%gslist-prepend-sap "g_slist_prepend") () pointer
+ (gslist pointer)
+ (data pointer))
+
+(defun make-gslist (type list)
+ (let ((new-element (ecase (alien-type type)
+ (system-area-pointer #'%gslist-prepend-sap)
+ ((signed-byte c-call:short c-call:int c-call:long)
+ #'%gslist-prepend-signed)
+ ((unsigned-byte c-call:unsigned-short
+ c-call:unsigned-int c-call:unsigned-long)
+ #'%gslist-prepend-unsigned)))
+ (to-alien (to-alien-function type)))
+ (loop
+ for element in (reverse list)
+ as gslist = (funcall new-element (or gslist (make-pointer 0))
+ (funcall to-alien element))
+ finally (return gslist))))
+
+(defbinding (gslist-free "g_slist_free") () nil
+ (gslist pointer))
+
+
+(defmethod alien-type ((type (eql 'gslist)) &rest args)
+ (declare (ignore type args))
+ (alien-type 'pointer))
+
+(defmethod size-of ((type (eql 'gslist)) &rest args)
+ (declare (ignore type args))
+ (size-of 'pointer))
+
+(defmethod to-alien-form (list (type (eql 'gslist)) &rest args)
+ (declare (ignore type))
+ (destructuring-bind (element-type) args
+ `(make-sglist ',element-type ,list)))
+
+(defmethod to-alien-function ((type (eql 'gslist)) &rest args)
+ (declare (ignore type))
+ (destructuring-bind (element-type) args
+ #'(lambda (list)
+ (make-gslist element-type list))))
+
+(defmethod from-alien-form (gslist (type (eql 'gslist)) &rest args)
+ (declare (ignore type))
+ (destructuring-bind (element-type) args
+ `(let ((gslist ,gslist))
+ (unwind-protect
+ (map-glist 'list #'identity gslist ',element-type)
+ (gslist-free gslist)))))
+
+(defmethod from-alien-function ((type (eql 'gslist)) &rest args)
+ (declare (ignore type))
+ (destructuring-bind (element-type) args
+ #'(lambda (gslist)
+ (unwind-protect
+ (map-glist 'list #'identity gslist element-type)
+ (gslist-free gslist)))))
+
+(defmethod cleanup-form (list (type (eql 'gslist)) &rest args)
+ (declare (ignore type args))
+ `(gslist-free ,list))
+
+(defmethod cleanup-function ((type (eql 'gslist)) &rest args)
+ (declare (ignore type args))
+ #'gslist-free)
+
+
+
+;;; Vector
+
+(defun make-c-vector (type length &optional content location)
+ (let* ((size-of-type (size-of type))
+ (location (or location (allocate-memory (* size-of-type length))))
+ (writer (writer-function type)))
+ (etypecase content
+ (vector
+ (loop
+ for element across content
+ for i from 0 below length
+ as offset = 0 then (+ offset size-of-type)
+ do (funcall writer element location offset)))
+ (list
+ (loop
+ for element in content
+ for i from 0 below length
+ as offset = 0 then (+ offset size-of-type)
+ do (funcall writer element location offset))))
+ location))
+
+
+(defun map-c-vector (seqtype function location element-type length)
+ (let ((reader (reader-function element-type))
+ (size-of-element (size-of element-type)))
+ (case seqtype
+ ((nil)
+ (loop
+ for i from 0 below length
+ as offset = 0 then (+ offset size-of-element)
+ do (funcall function (funcall reader location offset))))
+ (list
+ (loop
+ for i from 0 below length
+ as offset = 0 then (+ offset size-of-element)
+ collect (funcall function (funcall reader location offset))))
+ (t
+ (loop
+ with sequence = (make-sequence seqtype length)
+ for i from 0 below length
+ as offset = 0 then (+ offset size-of-element)
+ do (setf
+ (elt sequence i)
+ (funcall function (funcall reader location offset)))
+ finally (return sequence))))))
+
+
+(defmethod alien-type ((type (eql 'vector)) &rest args)
+ (declare (ignore type args))
+ (alien-type 'pointer))
+
+(defmethod size-of ((type (eql 'vector)) &rest args)
+ (declare (ignore type args))
+ (size-of 'pointer))
+
+(defmethod to-alien-form (vector (type (eql 'vector)) &rest args)
+ (declare (ignore type))
+ (destructuring-bind (element-type &optional (length '*)) args
+ (if (eq length '*)
+ `(let* ((vector ,vector)
+ (location (sap+
+ (allocate-memory (+ ,+size-of-int+
+ (* ,(size-of element-type)
+ (length vector))))
+ ,+size-of-int+)))
+ (make-c-vector ',element-type (length vector) vector location)
+ (setf (sap-ref-32 location ,(- +size-of-int+)) (length vector))
+ location)
+ `(make-c-vector ',element-type ,length ,vector))))
+
+(defmethod from-alien-form (location (type (eql 'vector)) &rest args)
+ (declare (ignore type))
+ (destructuring-bind (element-type &optional (length '*)) args
+ (if (eq length '*)
+ (error "Can't use vector of variable size as return type")
+ `(map-c-vector 'vector #'identity ',element-type ',length ,location))))
+
+(defmethod cleanup-form (location (type (eql 'vector)) &rest args)
+ (declare (ignore type))
+ (destructuring-bind (element-type &optional (length '*)) args
+ `(let* ((location ,location)
+ (length ,(if (eq length '*)
+ `(sap-ref-32 location ,(- +size-of-int+))
+ length)))
+ (loop
+ with destroy = (destroy-function ',element-type)
+ for i from 0 below length
+ as offset = 0 then (+ offset ,(size-of element-type))
+ do (funcall destroy location offset))
+ (deallocate-memory ,(if (eq length '*)
+ `(sap+ location ,(- +size-of-int+))
+ 'location)))))