This section describes how to implement a new port type in C. Although
ports support many operations, as a data structure they present an
opaque interface to the user. To the port implementor, you have two
pieces of information to work with: the port type, and the port’s
“stream”. The port type is an opaque pointer allocated when defining
your port type. It is your key into the port API, and it helps you
identify which ports are actually yours. The “stream” is a pointer
you control, and which you set when you create a port. Get a stream
from a port using the
SCM_STREAM macro. Note that your port
methods are only ever called with ports of your type.
A port type is created by calling
scm_make_port_type. Once you
have your port type, you can create ports with
Define a new port type. The name, read and write parameters are initial values for those port type fields, as described below. The other fields are initialized with default values and can be changed later.
Make a port with the given type. The stream indicates the
private data associated with the port, which your port implementation
may later retrieve with
SCM_STREAM. The mode bits should include
one or more of the flags
that the port is an input and/or an output port, respectively. The mode
bits may also include
that the port should be unbuffered or line-buffered, respectively. The
default is that the port will be block-buffered. See Buffering.
As you would imagine, encoding and conversion_strategy
specify the port’s initial textual encoding and conversion strategy.
Both are symbols.
scm_c_make_port is the same as
scm_c_make_port_with_encoding, except it uses the default port
encoding and conversion strategy.
The port type has a number of associate procedures and properties which collectively implement the port’s behavior. Creating a new port type mostly involves writing these procedures.
A pointer to a NUL terminated string: the name of the port type. This
property is initialized via the first argument to
read implementation fills read buffers. It should copy
bytes to the supplied bytevector
dst, starting at offset
start and continuing for
count bytes, returning the number
of bytes read.
write implementation flushes write buffers to the
It should write out bytes from the supplied bytevector
starting at offset
start and continuing for
and return the number of bytes that were written.
If a port’s
write function returns
-1, that indicates that reading or writing would block. In that case
to preserve the illusion of a blocking read or write operation, Guile’s
C port run-time will
poll on the file descriptor returned by
either the port’s
Only a port type which implements the
write_wait_fd port methods can usefully return
from a read or write function. See Non-Blocking I/O, for more on
non-blocking I/O in Guile.
write is called on the port, to print a port
description. For example, for a file port it may produce something
#<input: /etc/passwd 3>. Set using
The first argument port is the port being printed, the second argument dest_port is where its description should go.
Called when the port is closed. It should free any resources used by the port. Set using
By default, ports that are garbage collected just go away without closing. If your port type needs to release some external resource like a file descriptor, or needs to make sure that its internal buffers are flushed even if the port is collected while it was open, then mark the port type as needing a close on GC.
Set the current position of the port. Guile will flush read and/or write buffers before seeking, as appropriate.
Truncate the port data to be specified length. Guile will flush buffers before hand, as appropriate. Set using
Determine whether this port is a random-access port.
Seeking on a random-access port with buffered input, or switching to
writing after reading, will cause the buffered input to be discarded and
Guile will seek the port back the buffered number of bytes. Likewise
seeking on a random-access port with buffered output, or switching to
reading after writing, will flush pending bytes with a call to the
write procedure. See Buffering.
Indicate to Guile that your port needs this behavior by returning a
nonzero value from your
random_access_p function. The default
implementation of this function returns nonzero if the port type
supplies a seek implementation.
Guile will internally attach buffers to ports. An input port always has a read buffer and an output port always has a write buffer. See Buffering. A port buffer consists of a bytevector, along with some cursors into that bytevector denoting where to get and put data.
Port implementations generally don’t have to be concerned with
buffering: a port type’s
write function will
receive the buffer’s bytevector as an argument, along with an offset and
a length into that bytevector, and should then either fill or empty that
bytevector. However in some cases, port implementations may be able to
provide an appropriate default buffer size to Guile.
Fill in read_buf_size and write_buf_size with an appropriate buffer size for this port, if one is known.
File ports implement a
get_natural_buffer_sizes to let the
operating system inform Guile about the appropriate buffer sizes for the
particular file opened by the port.
Note that calls to all of these methods can proceed in parallel and
concurrently and from any thread up until the point that the port is
closed. The call to
close will happen when no other method is
running, and no method will be called after the
close method is
called. If your port implementation needs mutual exclusion to prevent
concurrency, it is responsible for locking appropriately.