Initial checkin
[clg] / gio / streams.lisp
diff --git a/gio/streams.lisp b/gio/streams.lisp
new file mode 100644 (file)
index 0000000..186cb0c
--- /dev/null
@@ -0,0 +1,209 @@
+;; Common Lisp bindings for GTK+ 2.x
+;; Copyright 2008 Espen S. Johnsen <espen@users.sf.net>
+;;
+;; Permission is hereby granted, free of charge, to any person obtaining
+;; a copy of this software and associated documentation files (the
+;; "Software"), to deal in the Software without restriction, including
+;; without limitation the rights to use, copy, modify, merge, publish,
+;; distribute, sublicense, and/or sell copies of the Software, and to
+;; permit persons to whom the Software is furnished to do so, subject to
+;; the following conditions:
+;;
+;; The above copyright notice and this permission notice shall be
+;; included in all copies or substantial portions of the Software.
+;;
+;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+;; IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+;; CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+;; TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+;; SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+;; $Id: streams.lisp,v 1.1 2008/12/10 02:58:13 espen Exp $
+
+
+(in-package "GIO")
+
+(use-prefix "g")
+
+;;; Input streams 
+
+(defbinding input-stream-read (stream buffer &key length cancellable) gssize
+  (stream input-stream)
+  (buffer pointer)
+  (length gsize)
+  (cancellable (or null cancellable))
+  (nil gerror-signal :out))
+
+(defbinding input-stream-read-all (stream buffer &key length cancellable) boolean
+  (stream input-stream)
+  (buffer pointer)
+  (length gsize)
+  (bytes-read gsize :out)
+  (cancellable (or null cancellable))
+  (nil gerror-signal :out))
+
+(defbinding input-stream-skip (stream length &key cancellable) gssize
+  (stream input-stream)
+  (length gsize)
+  (cancellable (or null cancellable))
+  (nil gerror-signal :out))
+
+(defbinding input-stream-close (stream &key cancellable) boolean
+  (stream input-stream)
+  (cancellable (or null cancellable))
+  (nil gerror-signal :out))
+
+
+;;; Output streams 
+
+(defbinding output-stream-write (stream buffer &key length cancellable) gssize
+  (stream output-stream)
+  (buffer (or (unboxed-vector (unsigned-byte 8)) pointer))
+  ((or length (length buffer)) gsize)
+  (cancellable (or null cancellable))
+  (nil gerror-signal :out))
+
+(defbinding output-stream-write-all (stream buffer &key length cancellable) boolean
+  (stream output-stream)
+  (buffer (or (unboxed-vector (unsigned-byte 8)) pointer))
+  ((or length (length buffer)) gsize)
+  (bytes-written gsize :out)
+  (cancellable (or null cancellable))
+  (nil gerror-signal :out))
+
+(defbinding output-stream-flush (stream &key cancellable) boolean
+  (stream output-stream)
+  (cancellable (or null cancellable))
+  (nil gerror-signal :out))
+
+(defbinding output-stream-close (stream &key cancellable) boolean
+  (stream output-stream)
+  (cancellable (or null cancellable))
+  (nil gerror-signal :out))
+
+
+;;; Unix streams
+
+(defbinding %unix-input-stream-new () pointer
+  (fd int)
+  (close-fd-p boolean))
+
+(defmethod allocate-foreign ((stream unix-input-stream) &key fd close-fd)
+  (%unix-input-stream-new fd close-fd))
+
+(defbinding %unix-output-stream-new () pointer
+  (fd int)
+  (close-fd-p boolean))
+
+(defmethod allocate-foreign ((stream unix-output-stream) &key fd close-fd)
+  (%unix-output-stream-new fd close-fd))
+
+
+;;; Callback streams (clg extension)
+
+(define-callback callback-stream-read-func gssize 
+    ((buffer pointer) (count gsize) (cancellable (or null cancellable)) 
+     (gerror pointer) (stream-id pointer-data))
+  (declare (ignore cancellable))
+  (handler-case
+      (let* ((sequence (make-array count :element-type '(unsigned-byte 8)))
+            (stream (find-user-data stream-id))
+            (bytes-read (read-sequence sequence stream)))
+       (unless (null-pointer-p buffer)
+         (make-c-vector '(unsigned-byte 8) bytes-read 
+          :content sequence :location buffer))
+       bytes-read)
+    (serious-condition (condition)
+      (gerror-set-in-callback gerror (file-error-domain) 
+       (enum-int :failed 'file-error-enum) (princ-to-string condition))
+      -1)))
+
+(define-callback callback-stream-write-func gssize 
+    ((buffer pointer) (count gsize) (cancellable (or null cancellable)) 
+     (gerror pointer) (stream-id pointer-data))
+  (declare (ignore cancellable))
+  (handler-case
+      (let ((stream (find-user-data stream-id)))
+       (write-sequence
+        (map-c-vector 'vector 'identity buffer '(unsigned-byte 8) count)
+        stream))
+    (serious-condition (condition)
+      (gerror-set-in-callback gerror (file-error-domain) 
+       (enum-int :failed 'file-error-enum) (princ-to-string condition))
+      -1)))
+
+(define-callback callback-stream-flush-func boolean
+    ((cancellable (or null cancellable)) (gerror pointer)
+     (stream-id pointer-data))
+  (declare (ignore cancellable))
+  (handler-case (force-output (find-user-data stream-id))
+    (serious-condition (condition)
+      (gerror-set-in-callback gerror (file-error-domain) 
+       (enum-int :failed 'file-error-enum) (princ-to-string condition))
+      -1)))
+
+(define-callback callback-stream-close-func boolean
+    ((cancellable (or null cancellable)) gerror (stream-id pointer-data))
+  (declare (ignore cancellable gerror))
+  (destroy-user-data stream-id))
+
+(defbinding %callback-input-stream-new (stream-id) pointer
+  (callback-stream-read-func callback)
+  (callback-stream-close-func callback)
+  (stream-id pointer-data))
+
+(defbinding %callback-output-stream-new (stream-id) pointer
+  (callback-stream-read-func callback)
+  (callback-stream-flush-func callback)
+  (callback-stream-close-func callback)
+  (stream-id pointer-data))
+
+(defmethod allocate-foreign ((stream callback-input-stream) &key base-stream)
+  (%callback-input-stream-new (register-user-data base-stream)))
+
+(defmethod allocate-foreign ((stream callback-output-stream) &key base-stream)
+  (%callback-input-stream-new (register-user-data base-stream)))
+
+
+;;; Lisp integration
+
+(deftype input-stream-designator () '(or stream input-stream integer))
+(deftype output-stream-designator () '(or stream input-stream integer))
+
+(define-type-method alien-type ((type input-stream-designator))
+  (declare (ignore type))
+  (alien-type 'input-stream))
+
+(define-type-method alien-arg-wrapper ((type input-stream-designator) var stream style form &optional copy-in-p)
+  (declare (ignore type))
+  (let ((%stream (make-symbol "STREAM")))
+    `(let ((,%stream (etypecase ,stream
+                      (input-stream ,stream)
+                      (integer (make-instance 'unix-input-stream :fd ,stream))
+                      (stream (make-instance 'callback-input-stream 
+                               :base-stream ,stream)))))
+       (unwind-protect
+           ,(alien-arg-wrapper 'input-stream var %stream style form copy-in-p)
+        (unless (typep ,stream 'input-stream)
+          (input-stream-close ,%stream))))))
+
+(define-type-method alien-type ((type output-stream-designator))
+  (declare (ignore type))
+  (alien-type 'output-stream))
+
+(define-type-method alien-arg-wrapper ((type output-stream-designator) var stream style form &optional copy-in-p)
+  (declare (ignore type))
+  (let ((%stream (make-symbol "STREAM")))
+    `(let ((,%stream (etypecase ,stream
+                      (output-stream ,stream)
+                      (integer (make-instance 'unix-output-stream :fd ,stream))
+                      (stream (make-instance 'callback-output-stream 
+                               :base-stream ,stream)))))
+       (unwind-protect
+           ,(alien-arg-wrapper 'input-stream var %stream style form copy-in-p)
+        (unless (typep ,stream 'output-stream)
+          (output-stream-close ,%stream))))))
+
+;; TODO: make GIO streams appear as Lisp streams