@need 3200

@node Buffered File Descriptors
@chapter Buffered File Descriptors

These functions allow you to perform buffered I/O on descriptors
using the VU functions. (See @ref{A Virtual Unix File-System Interface}.)


Each buffered file is associated with these values:

@example
@group
     t_uchar * buffer;
             Storage for buffered characters.
             The location of the buffer in memory
             may change over time.
@end group
@group
@end group
@end example
@example
@group
     long bufsize
             The size of the buffer.
@end group
@group
@end group
@end example
@example
@group
     t_uchar * read_write_position;
             The read/write position, within the buffer.
             This corresponds to the file offset returned
             by:
                     vu_lseek (&errn, fd, 0, SEEK_CUR)
@end group
@group
@end group
@end example
@example
@group
     long buffered;
             The number of buffered characters relative
             to the read/write position.
@end group
@group
@end group
@end example
@example
@group
             All bytes between `buffer' and 
             `read_write_position + buffered' are
             buffered.
@end group
@group
@end group
@end example
@example
@group
             Note that `buffered' may be negative if the
             `read_write_position' is beyond the current
             end of the file.
@end group
@group
@end group
@end example

Normal I/O functions like @code{vu_read} and @code{vu_write} operate
in the expected way: they buffer characters or read characters
from the buffer, flushing or refilling it as needed.


For high-performance I/O, there is assistance for performing
buffered I/O without copying characters to and from the buffer:

@example
@group
             vfdbuf_getbuf
             vfdbuf_takebuf
             vfdbuf_set_buffer
             vfdbuf_more
             vfdbuf_advance
@end group
@group
@end group
@end example

@noindent
which are documented later in this chapter.


Buffers can be designated @code{dont_flush} -- which means that the buffer
grows rather than writing to an underlying file.  In combination with
pseudo-descriptors (see @strong{reserv_pseudo} in @ref{Reserved File Descriptors and Pseudo-Descriptors}), @code{dont_flush} buffers
can be used to implement in-core files (files which are actually 
strings).


Buffers can be designated @code{zero_byte} -- which means that an extra
byte is added to the buffer (at @code{buffer + bufsize}) and that byte
is initialized to @code{0}.

@menu
* Establishing Buffers::
* Controlling Buffer Flushing::
* Controlling Buffer Auto-shift::
* Access to Buffers::
* Controlling What is Buffered::
* The End-of-File::
@end menu

@need 3200

@node Establishing Buffers
@section Establishing Buffers
@sp 1
@need 1750
@noindent
@b{* Function} @code{vfdbuf_buffer_fd}@fuindex vfdbuf_buffer_fd
@*
@example
@group
int vfdbuf_buffer_fd (int * errn,
                      int fd,
                      long bufsize,
                      int flags,
                      int buffer_flags);
@end group
@group
@end group
@end example

Arrange to buffer I/O on descriptor @code{fd}.


@code{fd} is the descriptor to buffer.


@code{bufsize} is the initial size of the buffer or @code{0} to use a buffer of
the default size.


@code{flags} indicates whether to buffer for input (@code{O_RDONLY}),
output (@code{O_WRONLY}) or both (@code{O_RDWR}).


@strong{WARNING:} I am fairly sure that there are bugs in the 
buffering code, especially for @code{O_RDWR} files.  Some 
comprehensive unit tests are needed for this module.


@code{buffer_flags} is a combination (@code{|}) of any of the bits:

@example
@group
     vfdbuf_add_zero_byte
     vfdbuf_auto_shift
@end group
@group
@end group
@end example

If @code{vfdbuf_add_zero_byte} is set, the actual buffer size for this
descriptor is one byte larger than @code{bufsize} (even if the buffer is
reallocated).  The extra byte is initialized to @code{0}.


If @code{vfdbuf_auto_shift} is set, the behavior of @code{vfdbuf_more} is
modified.  See @strong{vfdbuf_more} in @ref{Controlling What is Buffered}.


If @code{fd} is already buffered, this function attempts to reset the
buffer size, flags, and buffer flags.  If more than @code{bufsize}
characters are already buffered, the resulting buffer will be
larger than @code{bufsize}.


Return @code{0} on success, @code{-1} (and set @code{*errn}) on error.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vfdbuf_set_buffer}@fuindex vfdbuf_set_buffer
@*
@example
@group
int
vfdbuf_set_buffer (int * errn,
                   int fd,
                   t_uchar * buffer,
                   long bufsize,
@end group
@group
                   long read_write_pos,
                   long buffered,
                   int add_zero_byte,
                   void (*free_buffer)(t_uchar * buf, void * closure),
                   void * free_buffer_closure)
@end group
@group
@end group
@end example

Establish a specific region of memory as the buffer for @code{fd}.


See @ref{Buffered File Descriptors} and @strong{vfdbuf_buffer_fd}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vfdbuf_is_buffered}@fuindex vfdbuf_is_buffered
@*
@example
@group
int vfdbuf_is_buffered (int fd);
@end group
@group
@end group
@end example

Return @code{1} if fd has a (vfdbuf) buffer, @code{0} otherwise.




@need 3200

@node Controlling Buffer Flushing
@section Controlling Buffer Flushing
@sp 1
@need 1750
@noindent
@b{* Function} @code{vfdbuf_set_dont_flush}@fuindex vfdbuf_set_dont_flush
@*
@example
@group
int vfdbuf_set_dont_flush (int * errn, int fd, int setting);
@end group
@group
@end group
@end example

Activate or deactivate buffer flushing for descriptor @code{fd}.


@code{setting} is @code{0} to deactivate and any other value to activate
flushing.


If flushing is deactivated, writes may cause the size of the buffer
to be increased and calls to @code{vfdbuf_flush} have no effect.


Return @code{-1} and EINVAL if @code{fd} is not buffered, @code{0} otherwise.


See also @strong{vfdbuf_is_dont_flush}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vfdbuf_is_dont_flush}@fuindex vfdbuf_is_dont_flush
@*
@example
@group
int vfdbuf_is_dont_flush (int * errn, int fd);
@end group
@group
@end group
@end example

Return @code{0} if fd is buffered and flushing is enabled,
a positive value if fd is buffered and flushing is disabled.


Return @code{-1} and EINVAL if fd is not buffered.




@need 3200

@node Controlling Buffer Auto-shift
@section Controlling Buffer Auto-shift
@sp 1
@need 1750
@noindent
@b{* Function} @code{vfdbuf_set_auto_shift}@fuindex vfdbuf_set_auto_shift
@*
@example
@group
int vfdbuf_set_auto_shift (int * errn, int fd, int setting);
@end group
@group
@end group
@end example

Activate or deactivate buffer auto-shift for descriptor @code{fd}.


@code{setting} is @code{0} to deactivate and any other value to activate
auto-shift.


See @strong{vfdbuf_more} in @ref{Controlling What is Buffered}.


Return @code{-1} and EINVAL if @code{fd} is not buffered, @code{0} otherwise.


See also @strong{vfdbuf_is_auto_shift}.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vfdbuf_is_auto_shift}@fuindex vfdbuf_is_auto_shift
@*
@example
@group
int vfdbuf_is_auto_shift (int * errn, int fd);
@end group
@group
@end group
@end example

Return @code{0} if fd is buffered and auto-shift is disabled,
a positive value if fd is buffered and auto-shift is enabled.


Return @code{-1} and EINVAL if fd is not buffered.




@need 3200

@node Access to Buffers
@section Access to Buffers
@sp 1
@need 1750
@noindent
@b{* Function} @code{vfdbuf_getbuf}@fuindex vfdbuf_getbuf
@*
@example
@group
int vfdbuf_getbuf (int * errn,
                   t_uchar ** buffer,
                   long * bufsize,
                   t_uchar ** read_write_position,
                   long * buffered,
                   int fd);
@end group
@group
@end group
@end example

Return the address and size of the buffer and the address (within
that buffer) and number of buffered characters beyond the
read/write position for descriptor @code{fd}.


Upon return, @code{*buf} is the read/write position and @code{*buffered} is
the number of buffered characters beyond that position.  If
@code{*buffered} is less than @code{0}, then the characters between @code{*buffer}
and @code{*buffer - *buffered} are not yet part of the file (the read/write
position is beyond the end of the file).


Any of @code{buffer}, @code{bufsize}, @code{read_write_pos} or @code{buffered} may be
@code{0}.


Return @code{-1} and EINVAL if @code{fd} is not buffered, @code{0} otherwise.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vfdbuf_takebuf}@fuindex vfdbuf_takebuf
@*
@example
@group
int vfdbuf_takebuf (int * errn,
                    t_uchar ** bufbase,
                    long * bufsize,
                    t_uchar ** read_write_pos,
                    long * buffered,
                    int fd,
                    void (*free_buffer)(t_uchar * buf, void * closure),
                    void * free_buffer_closure);
@end group
@group
@end group
@end example

Return the address of and size of the buffer for @code{fd}.  Also return
the address of and number of buffered characters beyond the
read/write position.  (See @code{vfdbuf_getbuf}.)


Responsibility for freeing the buffer returned (allocated by
@code{must_malloc}) rests with the caller.  @code{vfdbuf} functions will continue
to use the buffer.  When the @code{vfdbuf} functions no longer require
the buffer, they call @code{free_buffer}: 

@example
@group
             free_buffer (buffer, free_buffer_closure)
@end group
@group
@end group
@end example

Subsequent calls to @code{vfdbuf_takebuf}, made before @code{free_buffer} is
called will return the same buffer if the same values are passed
for @code{free_buffer} and @code{free_buffer_closure} and a newly allocated
buffer otherwise.




@need 3200

@node Controlling What is Buffered
@section Controlling What is Buffered
@sp 1
@need 1750
@noindent
@b{* Function} @code{vfdbuf_shift}@fuindex vfdbuf_shift
@*
@example
@group
int vfdbuf_shift (int * errn, int fd, long amt);
@end group
@group
@end group
@end example

@strong{WARNING: there is a note in the code that says documentation
for this function is out of date.}


Discard @code{amt} leading characters from a buffer, shifting any
remaining characters to make room at the end of the buffer.


If the @geindex don't flush
@dfn{don't flush} flag is set for this buffer, this call will
increase the size of the buffer by @code{amt} characters and leave existing
characters untouched.


If @code{amt} is larger than the number of buffered characters that
preceed the read/write position, or if @code{amt} is @code{-1}, the effect is
the same as if @code{amt} were exactly the number of buffered characters
that preceed the read/write position.


If the buffer is being used for output, this call will first flush
shifted characters that are currently part of the file.  If there
are characters in the buffer beyond the end of the file, however, they
are not flushed by this function.  The effect is that this function
will not make a file larger. (See @code{vfdbuf_buffer_to_position}.)


Return @code{0} upon success, @code{-1} upon error.  This function can fail for a
descriptor opened for writing if it was necessary to flush
characters from the buffer, but the flush operation failed.


One useful post-condition of this function is that there is room
for @code{amt} more characters beyond the read/write position after a
call to this function than were available before.


Another useful post-condition is that the read/write position
within the file is not changed by this function. (See
@code{vfdbuf_advance}.)

@sp 1
@need 1750
@noindent
@b{* Function} @code{vfdbuf_advance}@fuindex vfdbuf_advance
@*
@example
@group
int vfdbuf_advance (int * errn, int fd, long amt);
@end group
@group
@end group
@end example

Advance the read/write position of a buffered descriptor.


If @code{amt} is larger than the number of buffered characters beyond
the read/write position, the size of the buffer is increased, and
the new characters initialized to @code{0}, but no new characters are read
from the descriptor.


One or more calls this function are commonly followed by a call
to @code{vfdbuf_shift} to discard the advanced-over characters from the 
buffer.  A good time to make such a call is before a call to 
@code{vfdbuf_more}, if it is safe to discard characters from the buffer
at that time.


Return @code{-1} and EINVAL if @code{fd} is not buffered, @code{0} otherwise.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vfdbuf_flush}@fuindex vfdbuf_flush
@*
@example
@group
int vfdbuf_flush (int * errn, int fd);
@end group
@group
@end group
@end example

Write buffered characters prior to the read/write position to disk.
This function has no effect if descriptor @code{fd} is not buffered, or
if the @geindex don't flush
@dfn{don't flush} flag is set for this descriptor.  (See
@code{vfdbuf_set_dont_flush}.)


Flushed characters are removed from the buffer.


The read/write position may be past the last character of the file.
In that case, only the characters in the file are flushed to disk.
(See @code{vfdbuf_buffer_to_position}.)


Return @code{0} upon success, @code{-1} upon error.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vfdbuf_return}@fuindex vfdbuf_return
@*
@example
@group
int vfdbuf_return (int * errn, int fd, t_uchar * str, long len);
@end group
@group
@end group
@end example

Add characters to the buffer for descriptor @code{fd}.


Characters are inserted immediately after the read/write position
so that subsequent reads on this descriptor return those characters
first and subsequent writes overwrite them.  Subsequent flushes of
a writable descriptor will ignore these characters unless the
read/write position is first advanced by a write or by
@code{vfdbuf_advance}.


If @code{fd} is a read-only descriptor, buffered characters prior to 
the read/write position may be overwritten.


The read/write position of the descriptor is unchanged relative to
the beginning of the file by calls to this function.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vfdbuf_more}@fuindex vfdbuf_more
@*
@example
@group
int vfdbuf_more (int * errn,
                 t_uchar ** buffer,
                 long * bufsize,
                 t_uchar ** read_write_pos,
                 long * buffered,
                 int fd,
                 long opt_amt);
@end group
@group
@end group
@end example

Buffer (by reading) additional characters for descriptor @code{fd}.
Return the address of and number of buffered unread characters
(including previously buffered but unread characters).


@code{opt_amt} is the number of additional characters to read or @code{0} to
read a default number of additional characters.


Ordinarily, no characters are discarded from the buffer by this
function.  (See @code{vfdbuf_advance} and @code{vfdbuf_shift}.)


If the buffer was created with the flag @code{vfdbuf_auto_shift},
@code{opt_amt} is @code{0}, and the last buffered character is more than 3/4 of
the way through the buffer's allocated memory, then @code{vfdbuf_more}
will call @code{vfdbuf_shift} before doing anything else.  This is the
only circumstance under which @code{vfdbuf_more} will discard characters
from a buffer.


The read/write position is not changed by this function.


Return @code{-1} upon error, the number of characters read upon success.




@need 3200

@node The End-of-File
@section The End-of-File
@sp 1
@need 1750
@noindent
@b{* Function} @code{vfdbuf_is_eof}@fuindex vfdbuf_is_eof
@*
@example
@group
int vfdbuf_is_eof (int * errn, int fd);
@end group
@group
@end group
@end example

Return @code{1} value if the end of file has been reached while
reading from buffered descriptor @code{fd}, @code{0} otherwise.


Return @code{-1} and EINVAL if @code{fd} is not a buffered descriptor.

@sp 1
@need 1750
@noindent
@b{* Function} @code{vfdbuf_clear_eof}@fuindex vfdbuf_clear_eof
@*
@example
@group
void vfdbuf_clear_eof (int * errn, int fd);
@end group
@group
@end group
@end example

Clear the eof flag for buffered file descriptor @code{fd}.


Return @code{-1} and EINVAL if @code{fd} is not a buffered descriptor.







