6.12.10.4 Custom Ports

Custom ports allow the user to provide input and handle output via user-supplied procedures. Guile currently only provides custom binary ports, not textual ports; for custom textual ports, See Soft Ports. We should add the R6RS custom textual port interfaces though. Contributions are appreciated.

Scheme Procedure: make-custom-binary-input-port id read! get-position set-position! close

Return a new custom binary input port16 named id (a string) whose input is drained by invoking read! and passing it a bytevector, an index where bytes should be written, and the number of bytes to read. The read! procedure must return an integer indicating the number of bytes read, or 0 to indicate the end-of-file.

Optionally, if get-position is not #f, it must be a thunk that will be called when port-position is invoked on the custom binary port and should return an integer indicating the position within the underlying data stream; if get-position was not supplied, the returned port does not support port-position.

Likewise, if set-position! is not #f, it should be a one-argument procedure. When set-port-position! is invoked on the custom binary input port, set-position! is passed an integer indicating the position of the next byte is to read.

Finally, if close is not #f, it must be a thunk. It is invoked when the custom binary input port is closed.

The returned port is fully buffered by default, but its buffering mode can be changed using setvbuf (see Buffering).

Using a custom binary input port, the open-bytevector-input-port procedure (see Bytevector Ports) could be implemented as follows:

(define (open-bytevector-input-port source)
  (define position 0)
  (define length (bytevector-length source))

  (define (read! bv start count)
    (let ((count (min count (- length position))))
      (bytevector-copy! source position
                        bv start count)
      (set! position (+ position count))
      count))

  (define (get-position) position)

  (define (set-position! new-position)
    (set! position new-position))

  (make-custom-binary-input-port "the port" read!
                                  get-position set-position!
                                  #f))

(read (open-bytevector-input-port (string->utf8 "hello")))
⇒ hello
Scheme Procedure: make-custom-binary-output-port id write! get-position set-position! close

Return a new custom binary output port named id (a string) whose output is sunk by invoking write! and passing it a bytevector, an index where bytes should be read from this bytevector, and the number of bytes to be “written”. The write! procedure must return an integer indicating the number of bytes actually written; when it is passed 0 as the number of bytes to write, it should behave as though an end-of-file was sent to the byte sink.

The other arguments are as for make-custom-binary-input-port.

Scheme Procedure: make-custom-binary-input/output-port id read! write! get-position set-position! close

Return a new custom binary input/output port named id (a string). The various arguments are the same as for The other arguments are as for make-custom-binary-input-port and make-custom-binary-output-port. If buffering is enabled on the port, as is the case by default, input will be buffered in both directions; See Buffering. If the set-position! function is provided and not #f, then the port will also be marked as random-access, causing the buffer to be flushed between reads and writes.


Footnotes

(16)

This is similar in spirit to Guile’s soft ports (see Soft Ports).