The Hackerlab at `regexps.com`

## Buffered File Descriptors

up: libhackerlab next: Reserved File Descriptors and Pseudo-Descriptors prev: A VU Handler for the URL Socket Scheme

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

Each buffered file is associated with these values:

         t_uchar * buffer;
                 Storage for buffered characters.
                 The location of the buffer in memory
                 may change over time.

         long bufsize
                 The size of the buffer.

         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)

         long buffered;
                 The number of buffered characters relative
                 to the read/write position.

                 All bytes between `buffer' and
                 `read_write_position + buffered' are
                 buffered.

                 Note that `buffered' may be negative if the
                 `read_write_position' is beyond the current
                 end of the file.

Normal I/O functions like `vu_read` and `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:

                 vfdbuf_getbuf
                 vfdbuf_takebuf
                 vfdbuf_set_buffer
                 vfdbuf_more
                 vfdbuf_advance

which are documented later in this chapter.

Buffers can be designated `dont_flush` -- which means that the buffer grows rather than writing to an underlying file. In combination with pseudo-descriptors (see reserv_pseudo), `dont_flush` buffers can be used to implement in-core files (files which are actually strings).

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

- Establishing Buffers
- Controlling Buffer Flushing
- Controlling Buffer Auto-shift
- Access to Buffers
- Controlling What is Buffered
- The End-of-File

### Establishing Buffers

up: Buffered File Descriptors next: Controlling Buffer Flushing

Function `vfdbuf_buffer_fd`

    int vfdbuf_buffer_fd (int * errn,
                          int fd,
                          long bufsize,
                          int flags,
                          int buffer_flags);

Arrange to buffer I/O on descriptor `fd` .

`fd` is the descriptor to buffer.

`bufsize` is the initial size of the buffer or `0` to use a buffer of the default size.

`flags` indicates whether to buffer for input (`O_RDONLY` ), output (`O_WRONLY` ) or both (`O_RDWR` ).

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

`buffer_flags` is a combination (`|` ) of any of the bits:

         vfdbuf_add_zero_byte
         vfdbuf_auto_shift

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

If `vfdbuf_auto_shift` is set, the behavior of `vfdbuf_more` is modified. See vfdbuf_more.

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

Return `0` on success, `-1` (and set `*errn` ) on error.

Function `vfdbuf_set_buffer`

    int
    vfdbuf_set_buffer (int * errn,
                       int fd,
                       t_uchar * buffer,
                       long bufsize,
                       long read_write_pos,
                       long buffered,
                       int add_zero_byte,
                       void (*free_buffer)(t_uchar * buf, void * closure),
                       void * free_buffer_closure)

Establish a specific region of memory as the buffer for `fd` .

See Buffered File Descriptors and vfdbuf_buffer_fd.

Function `vfdbuf_is_buffered`

    int vfdbuf_is_buffered (int fd);

Return `1` if fd has a (vfdbuf) buffer, `0` otherwise.

### Controlling Buffer Flushing

up: Buffered File Descriptors next: Controlling Buffer Auto-shift prev: Establishing Buffers

Function `vfdbuf_set_dont_flush`

    int vfdbuf_set_dont_flush (int * errn, int fd, int setting);

Activate or deactivate buffer flushing for descriptor `fd` .

`setting` is `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 `vfdbuf_flush` have no effect.

Return `-1` and EINVAL if `fd` is not buffered, `0` otherwise.

See also vfdbuf_is_dont_flush.

Function `vfdbuf_is_dont_flush`

    int vfdbuf_is_dont_flush (int * errn, int fd);

Return `0` if fd is buffered and flushing is enabled, a positive value if fd is buffered and flushing is disabled.

Return `-1` and EINVAL if fd is not buffered.

### Controlling Buffer Auto-shift

up: Buffered File Descriptors next: Access to Buffers prev: Controlling Buffer Flushing

Function `vfdbuf_set_auto_shift`

    int vfdbuf_set_auto_shift (int * errn, int fd, int setting);

Activate or deactivate buffer auto-shift for descriptor `fd` .

`setting` is `0` to deactivate and any other value to activate auto-shift.

See vfdbuf_more.

Return `-1` and EINVAL if `fd` is not buffered, `0` otherwise.

See also vfdbuf_is_auto_shift.

Function `vfdbuf_is_auto_shift`

    int vfdbuf_is_auto_shift (int * errn, int fd);

Return `0` if fd is buffered and auto-shift is disabled, a positive value if fd is buffered and auto-shift is enabled.

Return `-1` and EINVAL if fd is not buffered.

### Access to Buffers

up: Buffered File Descriptors next: Controlling What is Buffered prev: Controlling Buffer Auto-shift

Function `vfdbuf_getbuf`

    int vfdbuf_getbuf (int * errn,
                       t_uchar ** buffer,
                       long * bufsize,
                       t_uchar ** read_write_position,
                       long * buffered,
                       int fd);

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 `fd` .

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

Any of `buffer` , `bufsize` , `read_write_pos` or `buffered` may be `0` .

Return `-1` and EINVAL if `fd` is not buffered, `0` otherwise.

Function `vfdbuf_takebuf`

    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);

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

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

                 free_buffer (buffer, free_buffer_closure)

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

### Controlling What is Buffered

up: Buffered File Descriptors next: The End-of-File prev: Access to Buffers

Function `vfdbuf_shift`

    int vfdbuf_shift (int * errn, int fd, long amt);

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

Discard `amt` leading characters from a buffer, shifting any remaining characters to make room at the end of the buffer.

If the don't flush flag is set for this buffer, this call will increase the size of the buffer by `amt` characters and leave existing characters untouched.

If `amt` is larger than the number of buffered characters that preceed the read/write position, or if `amt` is `-1` , the effect is the same as if `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 `vfdbuf_buffer_to_position` .)

Return `0` upon success, `-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 `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 `vfdbuf_advance` .)

Function `vfdbuf_advance`

    int vfdbuf_advance (int * errn, int fd, long amt);

Advance the read/write position of a buffered descriptor.

If `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 `0` , but no new characters are read from the descriptor.

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

Return `-1` and EINVAL if `fd` is not buffered, `0` otherwise.

Function `vfdbuf_flush`

    int vfdbuf_flush (int * errn, int fd);

Write buffered characters prior to the read/write position to disk. This function has no effect if descriptor `fd` is not buffered, or if the don't flush flag is set for this descriptor. (See `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 `vfdbuf_buffer_to_position` .)

Return `0` upon success, `-1` upon error.

Function `vfdbuf_return`

    int vfdbuf_return (int * errn, int fd, t_uchar * str, long len);

Add characters to the buffer for descriptor `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 `vfdbuf_advance` .

If `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.

Function `vfdbuf_more`

    int vfdbuf_more (int * errn,
                     t_uchar ** buffer,
                     long * bufsize,
                     t_uchar ** read_write_pos,
                     long * buffered,
                     int fd,
                     long opt_amt);

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

`opt_amt` is the number of additional characters to read or `0` to read a default number of additional characters.

Ordinarily, no characters are discarded from the buffer by this function. (See `vfdbuf_advance` and `vfdbuf_shift` .)

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

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

Return `-1` upon error, the number of characters read upon success.

### The End-of-File

up: Buffered File Descriptors prev: Controlling What is Buffered

Function `vfdbuf_is_eof`

    int vfdbuf_is_eof (int * errn, int fd);

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

Return `-1` and EINVAL if `fd` is not a buffered descriptor.

Function `vfdbuf_clear_eof`

    void vfdbuf_clear_eof (int * errn, int fd);

Clear the eof flag for buffered file descriptor `fd` .

Return `-1` and EINVAL if `fd` is not a buffered descriptor.

libhackerlab: The Hackerlab C Library
The Hackerlab at `regexps.com`