Liam Healy asks:
Is it possible to share/send a stream with a foreign function? I would
like to have with-open-file open a file, then give the stream (or some
mapping of that stream) to a C function that expects a (C) stream (e.g.,
something that would result from the C function fopen). This C function
would put output to that stream and then return to the calling CL
function.
How about using the foreign function interface to make lisp equivalents of
fopen and friends? I do this sometimes to speed up IO, e.g.:
(load "" :unreferenced-lib-names (list (ff:convert-to-lang "fopen" :language :c)))
(load "" :unreferenced-lib-names (list (ff:convert-to-lang "fclose" :language :c)))
(load "" :unreferenced-lib-names (list (ff:convert-to-lang "getc" :language :c)))
(load "" :unreferenced-lib-names (list (ff:convert-to-lang "putc" :language :c)))
(FF:defforeign 'fopen :arguments '(simple-string simple-string) :return-type :fixnum)
(FF:defforeign 'fclose :arguments '(fixnum) :return-type :fixnum)
(FF:defforeign 'getc :arguments '(fixnum) :return-type :fixnum
:call-direct t :arg-checking nil :callback nil)
(FF:defforeign 'putc :arguments '(fixnum fixnum) :return-type :fixnum
:call-direct t :arg-checking nil :callback nil)
;; Define a pseudo-stream that keeps C-style port number, the associated filename and a boolean for
;; whether it is open or not.
(defstruct fast-io-stream filename port open?)
;; To open a fast-io-stream, call fopen and put the port in the appropriate struct. Valid directions
;; are :input :output :io (may not work without fseeks, etc.) and :append. All append streams are
;; read-write. There are lots of synonyms for these directions
(defun fast-io-open (filename &key (direction :input))
(setq direction
(cond
((member direction '("r" "read" "input" "in" read input in :input)
:test #'equal) "r")
((member direction '("w" "write" "output" "out" write output out :output)
:test #'equal) "w")
((member direction '("r+" "rw" "io" io :io) :test #'equal) "r+")
((member direction '("a" "a+" "append" append :append) :test #'equal) "a+")))
(make-fast-io-stream :filename filename :port (fopen filename direction) :open? t))
(defun fast-io-close (str)
(fclose (fast-io-stream-port str))
(setf (fast-io-stream-open? str) nil)
str)
(defun fast-io-read-char (str)
(code-char (getc (fast-io-stream-port str))))
(defun fast-io-write-char (char str)
(putc (char-code char) (fast-io-stream-port str)))
;; From here I imagine that you can build up a LISP interface to the stream
;; (e.g. with-open-fast-io-stream) as well as pass the port to your C code.
Larry