6.12.10.8 Low-Level Custom Ports in C

The make-custom-port procedure described in the previous section has similar functionality on the C level, though it is organized a bit differently.

In C, the mechanism is that one creates a new port type object. The methods are then associated with the port type object instead of the port itself. The port type object is an opaque pointer allocated when defining the port type, which serves as a key into the port API.

Ports themselves have associated stream values. The stream is a pointer controlled by the user, which is set when the port is created. Given a port, the SCM_STREAM macro returns its associated stream value, as a scm_t_bits. Note that your port methods are only ever called with ports of your type, so port methods can safely cast this value to the expected type. Contrast this to Scheme, which doesn’t need access to the stream because the make-custom-port methods can be closures that share port-specific data directly.

A port type is created by calling scm_make_port_type.

Function: scm_t_port_type* scm_make_port_type (char *name, size_t (*read) (SCM port, SCM dst, size_t start, size_t count), size_t (*write) (SCM port, SCM src, size_t start, size_t count))

Define a new port type. The name parameter is like the #:id parameter to make-custom-port; and read and write are like make-custom-port’s #:read and #:write, except that they should return (size_t)-1 if the read or write operation would block, instead of #f.

Function: void scm_set_port_read_wait_fd (scm_t_port_type *type, int (*wait_fd) (SCM port))
Function: void scm_set_port_write_wait_fd (scm_t_port_type *type, int (*wait_fd) (SCM port))
Function: void scm_set_port_print (scm_t_port_type *type, int (*print) (SCM port, SCM dest_port, scm_print_state *pstate))
Function: void scm_set_port_close (scm_t_port_type *type, void (*close) (SCM port))
Function: void scm_set_port_needs_close_on_gc (scm_t_port_type *type, int needs_close_p)
Function: void scm_set_port_seek (scm_t_port_type *type, scm_t_off (*seek) (SCM port, scm_t_off offset, int whence))
Function: void scm_set_port_truncate (scm_t_port_type *type, void (*truncate) (SCM port, scm_t_off length))
Function: void scm_set_port_random_access_p (scm_t_port_type *type, int (*random_access_p) (SCM port));
Function: void scm_set_port_input_waiting (scm_t_port_type *type, int (*input_waiting) (SCM port));
Function: void scm_set_port_get_natural_buffer_sizes (scm_t_port_type *type, void (*get_natural_buffer_sizes) (SCM, size_t *read_buf_size, size_t *write_buf_size))

Port method definitions. See Low-Level Custom Ports, for more details on each of these methods.

Once you have your port type, you can create ports with scm_c_make_port, or scm_c_make_port_with_encoding.

Function: SCM scm_c_make_port_with_encoding (scm_t_port_type *type, unsigned long mode_bits, SCM encoding, SCM conversion_strategy, scm_t_bits stream)
Function: SCM scm_c_make_port (scm_t_port_type *type, unsigned long mode_bits, scm_t_bits stream)

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.

At this point you may be wondering whether to implement your custom port type in C or Scheme. The answer is that probably you want to use Scheme’s make-custom-port. The speed is similar between C and Scheme, and ports implemented in C have the disadvantage of not being suspendable. See Non-Blocking I/O.