Soft ports are what Guile had before it had custom binary and textual ports, and allow for customizable textual input and output.
We recommend soft ports over R6RS custom textual ports because they are
easier to use while also being more expressive. R6RS custom textual
ports operate under the principle that a port has a mutable string
buffer, and this is reflected in the read
and write
procedures which take a buffer, offset, and length. However in Guile as
all ports have a byte buffer rather than some having a string buffer,
the R6RS interface imposes overhead and complexity.
Additionally, and unlike the R6RS interfaces, make-soft-port
from
the (ice-9 soft-ports)
module accepts keyword arguments, allowing
for its functionality to be extended over time.
If you find yourself needing more power, notably the ability to seek, probably you want to use low-level custom ports. See Low-Level Custom Ports.
(use-modules (ice-9 soft-ports))
Return a new port. If the read-string keyword argument is present, the port will be an input port. If write-string is present, the port will be an output port. If both are supplied, the port will be open for input and output.
When the port’s internal buffers are empty, read-string will be
called with no arguments, and should return a string, or #f
to
indicate end-of-stream. Similarly when a port flushes its write buffer,
the characters in that buffer will be passed to the write-string
procedure as its single argument. write-string returns
unspecified values.
If supplied, input-waiting? should return #t
if the soft
port has input which would be returned directly by read-string.
If supplied, close will be called when the port is closed, with no
arguments. If close-on-gc? is #t
, close will
additionally be called when the port becomes unreachable, after flushing
any pending write buffers.
With soft ports, the open-string-input-port
example from the
previous section is more simple:
(define (open-string-input-port source) (define already-read? #f) (define (read-string) (cond (already-read? "") (else (set! already-read? #t) source))) (make-soft-port #:id "strport" #:read-string read-string))
Note that there was an earlier form of make-soft-port
which was
exposed in Guile’s default environment, and which is still there. Its
interface is more clumsy and its users historically expect unbuffered
input. This interface will be deprecated, but we document it here.
Return a port capable of receiving or delivering characters as specified by the modes string (see open-file). pv must be a vector of length 5 or 6. Its components are as follows:
#f
) thunk for computing the number of
characters that can be read from the port without blocking.
For an output-only port only elements 0, 1, 2, and 4 need be
procedures. For an input-only port only elements 3 and 4 need
be procedures. Thunks 2 and 4 can instead be #f
if
there is no useful operation for them to perform.
If thunk 3 returns #f
or an eof-object
(see eof-object? in The Revised^5 Report on
Scheme) it indicates that the port has reached end-of-file.
For example:
(define stdout (current-output-port)) (define p (deprecated-make-soft-port (vector (lambda (c) (write c stdout)) (lambda (s) (display s stdout)) (lambda () (display "." stdout)) (lambda () (char-upcase (read-char))) (lambda () (display "@" stdout))) "rw")) (write p p) ⇒ #<input-output: soft 8081e20>