mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-05-20 19:50:24 +02:00
Add random_access_p port type method
* doc/ref/api-io.texi (I/O Extensions): Update documentation on implementing port types. Document get_natural_buffer_sizes. Document the new random_access_p. * libguile/fports.c (scm_i_fdes_to_port, fport_random_access_p): (scm_make_fptob): Instead of frobbing rw_random manually, implement a random_access_p function. * libguile/ports.c (default_random_access_p) (scm_set_port_random_access_p): New functions. scm_make_port_type, scm_c_make_port_with_encoding): Arrange for random_access_p to work.
This commit is contained in:
parent
704c42870d
commit
6ff542ee71
4 changed files with 71 additions and 61 deletions
|
@ -2263,72 +2263,20 @@ interface works internally.
|
||||||
@cindex ptob
|
@cindex ptob
|
||||||
@tindex scm_t_ptob_descriptor
|
@tindex scm_t_ptob_descriptor
|
||||||
@tindex scm_t_port
|
@tindex scm_t_port
|
||||||
@tindex scm_t_port_buffer
|
|
||||||
@findex SCM_PTAB_ENTRY
|
@findex SCM_PTAB_ENTRY
|
||||||
@findex SCM_PTOBNUM
|
@findex SCM_PTOBNUM
|
||||||
@vindex scm_ptobs
|
@vindex scm_ptobs
|
||||||
Guile's port facility consists of three main data structures. A port
|
Guile's port facility consists of two main data types: port type objects
|
||||||
type object (ptob) is of type @code{scm_t_ptob_descriptor}, and holds
|
and port instances. A port type object (or @dfn{ptob}) is of type
|
||||||
pointers to the methods that implement the port type. A port instance
|
@code{scm_t_ptob_descriptor}, and holds pointers to the methods that
|
||||||
is of type @code{scm_t_port}, and holds all state for the port. Finally
|
implement the port type. A port instance is of type @code{scm_t_port},
|
||||||
the read and write buffers are the @code{read_buf} and @code{write_buf}
|
and holds all state for the port.
|
||||||
members of the port instance, and are of type @code{scm_t_port_buffer}.
|
|
||||||
|
|
||||||
Given an @code{SCM} variable which points to a port, the corresponding C
|
Given an @code{SCM} variable which points to a port, the corresponding C
|
||||||
port object can be obtained using the @code{SCM_PTAB_ENTRY} macro. The
|
port object can be obtained using the @code{SCM_PTAB_ENTRY} macro. The
|
||||||
ptob can be obtained by using @code{SCM_PTOBNUM} to give an index into
|
ptob can be obtained by using @code{SCM_PTOBNUM} to give an index into
|
||||||
the @code{scm_ptobs} global array.
|
the @code{scm_ptobs} global array.
|
||||||
|
|
||||||
@subsubheading Port buffers
|
|
||||||
|
|
||||||
An input port always has a read buffer and an output port always has a
|
|
||||||
write buffer. @xref{Buffering}. These buffers are represented in C by
|
|
||||||
@code{scm_t_port_buffer} objects.
|
|
||||||
|
|
||||||
The port buffer consists of data as a byte array, pointed to by its
|
|
||||||
@code{buf} field. The valid data in the buffer is between the
|
|
||||||
@code{cur} and @code{end} indices into @code{buf}; @code{cur} must
|
|
||||||
always be less than or equal to @code{end}, which in turn must be less
|
|
||||||
than or equal to the buffer size @code{size}. The @code{buf} pointer is
|
|
||||||
actually a pointer to the start of a bytevector, stored in the
|
|
||||||
@code{bytevector} member. Using bytevectors to back port buffers allows
|
|
||||||
Scheme to manipulate these buffers.
|
|
||||||
|
|
||||||
``Valid data'' for a read buffer is data that has been buffered, but not
|
|
||||||
yet read by the user. A port's @code{read} procedure fills a read
|
|
||||||
buffer from the @code{end} element. For a write buffer, the ``valid
|
|
||||||
data'' is data which has been written by the user, but not yet flushed
|
|
||||||
to the mutable store. A port's @code{write} procedure will consume the
|
|
||||||
data between @code{cur} and @code{end} (not including @code{end}) and
|
|
||||||
advance @code{cur}.
|
|
||||||
|
|
||||||
The size of the buffers is controlled by the user, via @code{setvbuf}.
|
|
||||||
A port implementation can provide an idea of what the ``natural'' size
|
|
||||||
for its buffers are, but it has no guarantee that the buffer will be
|
|
||||||
those sizes. It's also possible for big reads or writes to work on
|
|
||||||
auxiliary buffers, and it's possible for @code{unget-bytevector} to
|
|
||||||
cause a read buffer to expand temporarily; port implementations can't
|
|
||||||
assume that the buffer they have been given to fill or empty corresponds
|
|
||||||
to the port's designated read or write buffer.
|
|
||||||
|
|
||||||
Port read buffers also have a flag indicating that the last read did not
|
|
||||||
advance @code{end}, which indicates end-of-stream. It is cleared by
|
|
||||||
Guile when Guile gives the user an EOF object.
|
|
||||||
|
|
||||||
@subsubheading The @code{rw_random} flag
|
|
||||||
|
|
||||||
Special treatment is required for ports which can be seeked at random.
|
|
||||||
Before various operations, such as seeking the port or changing from
|
|
||||||
input to output on a bidirectional port or vice versa. Seeking on a
|
|
||||||
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 port with
|
|
||||||
buffered output, or switching to reading after writing, will flush
|
|
||||||
pending bytes with a call to the @code{write} procedure. Indicate to
|
|
||||||
Guile that your port needs this behavior by setting the @code{rw_random}
|
|
||||||
flag. This flag is set by default if the port type supplies a seek
|
|
||||||
implementation.
|
|
||||||
|
|
||||||
@subsubheading C interface
|
@subsubheading C interface
|
||||||
|
|
||||||
A port type object is created by calling @code{scm_make_port_type}.
|
A port type object is created by calling @code{scm_make_port_type}.
|
||||||
|
@ -2403,6 +2351,46 @@ before hand, as appropriate. Set using
|
||||||
@deftypefun void scm_set_port_truncate (scm_t_bits tc, void (*truncate) (SCM port, scm_t_off length))
|
@deftypefun void scm_set_port_truncate (scm_t_bits tc, void (*truncate) (SCM port, scm_t_off length))
|
||||||
@end deftypefun
|
@end deftypefun
|
||||||
|
|
||||||
|
@item random_access_p
|
||||||
|
Determine whether this port is a random-access port.
|
||||||
|
|
||||||
|
@cindex random access
|
||||||
|
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
|
||||||
|
@code{write} procedure. @xref{Buffering}.
|
||||||
|
|
||||||
|
Indicate to Guile that your port needs this behavior by returning a
|
||||||
|
nonzero value from your @code{random_access_p} function. The default
|
||||||
|
implementation of this function returns nonzero if the port type
|
||||||
|
supplies a seek implementation.
|
||||||
|
|
||||||
|
@deftypefun void scm_set_port_random_access_p (scm_t_bits tc, int (*random_access_p) (SCM port));
|
||||||
|
@end deftypefun
|
||||||
|
|
||||||
|
@item 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.
|
||||||
|
@xref{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 @code{read} or @code{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.
|
||||||
|
|
||||||
|
@deftypefun void scm_set_port_get_natural_buffer_sizes @
|
||||||
|
(scm_t_bits tc, void (*get_natural_buffer_sizes) (SCM, size_t *read_buf_size, size_t *write_buf_size))
|
||||||
|
Fill in @var{read_buf_size} and @var{write_buf_size} with an appropriate buffer size for this port, if one is known.
|
||||||
|
@end deftypefun
|
||||||
|
|
||||||
|
File ports implement a @code{get_natural_buffer_sizes} to let the
|
||||||
|
operating system inform Guile about the appropriate buffer sizes for the
|
||||||
|
particular file opened by the port.
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
@node BOM Handling
|
@node BOM Handling
|
||||||
|
|
|
@ -418,7 +418,6 @@ scm_i_fdes_to_port (int fdes, long mode_bits, SCM name)
|
||||||
|
|
||||||
port = scm_c_make_port (scm_tc16_fport, mode_bits, (scm_t_bits)fp);
|
port = scm_c_make_port (scm_tc16_fport, mode_bits, (scm_t_bits)fp);
|
||||||
|
|
||||||
SCM_PTAB_ENTRY (port)->rw_random = SCM_FDES_RANDOM_P (fdes);
|
|
||||||
SCM_SET_FILENAME (port, name);
|
SCM_SET_FILENAME (port, name);
|
||||||
|
|
||||||
return port;
|
return port;
|
||||||
|
@ -639,6 +638,12 @@ fport_close (SCM port)
|
||||||
scm_syserror ("fport_close");
|
scm_syserror ("fport_close");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
fport_random_access_p (SCM port)
|
||||||
|
{
|
||||||
|
return SCM_FDES_RANDOM_P (SCM_FSTREAM (port)->fdes);
|
||||||
|
}
|
||||||
|
|
||||||
/* Query the OS to get the natural buffering for FPORT, if available. */
|
/* Query the OS to get the natural buffering for FPORT, if available. */
|
||||||
static void
|
static void
|
||||||
fport_get_natural_buffer_sizes (SCM port, size_t *read_size, size_t *write_size)
|
fport_get_natural_buffer_sizes (SCM port, size_t *read_size, size_t *write_size)
|
||||||
|
@ -663,6 +668,7 @@ scm_make_fptob ()
|
||||||
scm_set_port_seek (tc, fport_seek);
|
scm_set_port_seek (tc, fport_seek);
|
||||||
scm_set_port_truncate (tc, fport_truncate);
|
scm_set_port_truncate (tc, fport_truncate);
|
||||||
scm_set_port_input_waiting (tc, fport_input_waiting);
|
scm_set_port_input_waiting (tc, fport_input_waiting);
|
||||||
|
scm_set_port_random_access_p (tc, fport_random_access_p);
|
||||||
scm_set_port_get_natural_buffer_sizes (tc, fport_get_natural_buffer_sizes);
|
scm_set_port_get_natural_buffer_sizes (tc, fport_get_natural_buffer_sizes);
|
||||||
|
|
||||||
return tc;
|
return tc;
|
||||||
|
|
|
@ -196,6 +196,12 @@ scm_c_port_type_add_x (scm_t_ptob_descriptor *desc)
|
||||||
static SCM trampoline_to_c_read_subr;
|
static SCM trampoline_to_c_read_subr;
|
||||||
static SCM trampoline_to_c_write_subr;
|
static SCM trampoline_to_c_write_subr;
|
||||||
|
|
||||||
|
static int
|
||||||
|
default_random_access_p (SCM port)
|
||||||
|
{
|
||||||
|
return SCM_PORT_DESCRIPTOR (port)->seek != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
scm_t_bits
|
scm_t_bits
|
||||||
scm_make_port_type (char *name,
|
scm_make_port_type (char *name,
|
||||||
size_t (*read) (SCM port, SCM dst, size_t start,
|
size_t (*read) (SCM port, SCM dst, size_t start,
|
||||||
|
@ -215,6 +221,7 @@ scm_make_port_type (char *name,
|
||||||
desc->c_write = write;
|
desc->c_write = write;
|
||||||
desc->scm_read = read ? trampoline_to_c_read_subr : SCM_BOOL_F;
|
desc->scm_read = read ? trampoline_to_c_read_subr : SCM_BOOL_F;
|
||||||
desc->scm_write = write ? trampoline_to_c_write_subr : SCM_BOOL_F;
|
desc->scm_write = write ? trampoline_to_c_write_subr : SCM_BOOL_F;
|
||||||
|
desc->random_access_p = default_random_access_p;
|
||||||
|
|
||||||
ptobnum = scm_c_port_type_add_x (desc);
|
ptobnum = scm_c_port_type_add_x (desc);
|
||||||
|
|
||||||
|
@ -333,6 +340,13 @@ scm_set_port_input_waiting (scm_t_bits tc, int (*input_waiting) (SCM))
|
||||||
scm_c_port_type_ref (SCM_TC2PTOBNUM (tc))->input_waiting = input_waiting;
|
scm_c_port_type_ref (SCM_TC2PTOBNUM (tc))->input_waiting = input_waiting;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
scm_set_port_random_access_p (scm_t_bits tc, int (*random_access_p) (SCM))
|
||||||
|
{
|
||||||
|
scm_t_ptob_descriptor *ptob = scm_c_port_type_ref (SCM_TC2PTOBNUM (tc));
|
||||||
|
ptob->random_access_p = random_access_p;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
scm_set_port_get_natural_buffer_sizes
|
scm_set_port_get_natural_buffer_sizes
|
||||||
(scm_t_bits tc, void (*get_natural_buffer_sizes) (SCM, size_t *, size_t *))
|
(scm_t_bits tc, void (*get_natural_buffer_sizes) (SCM, size_t *, size_t *))
|
||||||
|
@ -721,9 +735,6 @@ scm_c_make_port_with_encoding (scm_t_bits tag, unsigned long mode_bits,
|
||||||
|
|
||||||
entry->internal = pti;
|
entry->internal = pti;
|
||||||
entry->file_name = SCM_BOOL_F;
|
entry->file_name = SCM_BOOL_F;
|
||||||
/* By default, any port type with a seek function has random-access
|
|
||||||
ports. */
|
|
||||||
entry->rw_random = ptob->seek != NULL;
|
|
||||||
entry->port = ret;
|
entry->port = ret;
|
||||||
entry->stream = stream;
|
entry->stream = stream;
|
||||||
entry->encoding = encoding;
|
entry->encoding = encoding;
|
||||||
|
@ -743,6 +754,8 @@ scm_c_make_port_with_encoding (scm_t_bits tag, unsigned long mode_bits,
|
||||||
|
|
||||||
initialize_port_buffers (ret);
|
initialize_port_buffers (ret);
|
||||||
|
|
||||||
|
entry->rw_random = ptob->random_access_p (ret);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -191,6 +191,7 @@ typedef struct scm_t_ptob_descriptor
|
||||||
|
|
||||||
void (*get_natural_buffer_sizes) (SCM port, size_t *read_size,
|
void (*get_natural_buffer_sizes) (SCM port, size_t *read_size,
|
||||||
size_t *write_size);
|
size_t *write_size);
|
||||||
|
int (*random_access_p) (SCM port);
|
||||||
|
|
||||||
int (*input_waiting) (SCM port);
|
int (*input_waiting) (SCM port);
|
||||||
|
|
||||||
|
@ -230,6 +231,8 @@ SCM_API void scm_set_port_truncate (scm_t_bits tc,
|
||||||
SCM_API void scm_set_port_input_waiting (scm_t_bits tc, int (*input_waiting) (SCM));
|
SCM_API void scm_set_port_input_waiting (scm_t_bits tc, int (*input_waiting) (SCM));
|
||||||
SCM_API void scm_set_port_get_natural_buffer_sizes
|
SCM_API void scm_set_port_get_natural_buffer_sizes
|
||||||
(scm_t_bits tc, void (*get_natural_buffer_sizes) (SCM, size_t *, size_t *));
|
(scm_t_bits tc, void (*get_natural_buffer_sizes) (SCM, size_t *, size_t *));
|
||||||
|
SCM_API void scm_set_port_random_access_p (scm_t_bits tc,
|
||||||
|
int (*random_access_p) (SCM port));
|
||||||
|
|
||||||
/* The input, output, error, and load ports. */
|
/* The input, output, error, and load ports. */
|
||||||
SCM_API SCM scm_current_input_port (void);
|
SCM_API SCM scm_current_input_port (void);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue