Next: Non-Blocking I/O, Previous: Using Ports from C, Up: Input and Output [Contents][Index]
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 scm_c_make_port
,
or scm_c_make_port_with_encoding
.
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 SCM_RDNG
or SCM_WRTNG
, indicating
that the port is an input and/or an output port, respectively. The mode
bits may also include SCM_BUF0
or SCM_BUFLINE
, indicating
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.
name
A pointer to a NUL terminated string: the name of the port type. This
property is initialized via the first argument to
scm_make_port_type
.
read
A port’s 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
A port’s write
implementation flushes write buffers to the
mutable store.
It should write out bytes from the supplied bytevector src
,
starting at offset start
and continuing for count
bytes,
and return the number of bytes that were written.
read_wait_fd
write_wait_fd
If a port’s read
or write
function returns (size_t)
-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 read_wait_fd
or write_wait_fd
function.
Set using
Only a port type which implements the read_wait_fd
or
write_wait_fd
port methods can usefully return (size_t) -1
from a read or write function. See Non-Blocking I/O, for more on
non-blocking I/O in Guile.
print
Called when write
is called on the port, to print a port
description. For example, for a file port it may produce something
like: #<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.
close
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.
seek
Set the current position of the port. Guile will flush read and/or write buffers before seeking, as appropriate.
truncate
Truncate the port data to be specified length. Guile will flush buffers before hand, as appropriate. Set using
random_access_p
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.
get_natural_buffer_sizes
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 read
or 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.
Next: Non-Blocking I/O, Previous: Using Ports from C, Up: Input and Output [Contents][Index]