int <seek function>(qpstream, qpmagic, whence, bufptr, sizeptr) QP_stream *qpstream; union QP_cookie *qpmagic; int whence; unsigned char **bufptr; size_t *sizeptr; Return Values: QP_SUCCESS QP_ERROR
The bottom layer seek function sets the stream qpstream
to a new
position based on the method whence
and the system-dependent
file address qpmagic
specified in the parameters.
The output parameter *bufptr
stores the beginning of the buffer
and *sizeptr
stores the size of record. When the bottom layer
seek function is called, the magic
field of qpstream
is the current stream position known to the user of the stream.
(It does not include the unconsumed characters in the buffer.)
Upon success, the seek function should return
QP_SUCCESS
and the magic
field of qpstream
should
be updated to the new position. Upon failure, it returns QP_ERROR
and suitable error code should be assigned to error
field of qpstream
.
The stream is set to a new position based on the whence
value and
qpmagic
values. (see fli-ios-sst-sda)
whence
is QP_BEGINNING
, the magic
field is the
system-dependent address to be positioned from the beginning of the
stream. If the seek_type
of the stream is QP_SEEK_PREVIOUS
,
the whence
value is always QP_BEGINNING
.
whence
is QP_CURRENT
, seeking is to be performed
from the current position. For instance, if byteno
is used for
magic
field of qpstream
, the stream should be set to the current
position (qpstream->magic.byteno
) plus the offset
specified in qpmagic->byteno
.
whence
is QP_END
, seeking is
to be performed from the end of file position associated with qpstream
.
For instance, if byteno
is used for
magic
field of qpstream
, the stream should be set to the size
of the file associated with qpstream
plus the offset
specified in qpmagic->byteno
.
Due to the buffering mechanism of a stream,
the magic
field in qpstream
might be different
from the actual position for the file (or other devices) associated
with the stream. For example, if the current record of an input stream
has a size of 10 and there are only 5 characters consumed, the magic
field indicates the position at the sixth character rather than the
11th character of the current record.
In short, the value in magic
field of qpstream
does not
count any characters in the buffer that are not consumed in an input
stream. For an output stream, the caller of the bottom layer seek
function will call flush function to flush output prior to calling this
function if qpstream
permits flushing (flush_type
is not
QP_FLUSH_ERROR
). The caller of this function
does not permit any seeking in an output stream with no flush permission
if there are characters in the current record (line position is not zero
in the output stream). However, if the bottom layer of an output
stream without flushing permission buffers more than one output record,
it is possible for the bottom layer seek function to be called with records
in the buffer. (This would be the case that there are no characters in
the current record.) The bottom layer seek function should write
out the records in the buffer for this case.
One effect of seeking is to clear out the buffer of a stream.
This should be adhered to in implementing the bottom layer seek function.
If qpstream
is an input stream, bufptr
and sizeptr
have the same meaning as in the bottom layer read function.
If qpstream
is an output stream, bufptr
and sizeptr
have the same meaning as in the bottom layer write function.
So for most of cases, *bufptr
should be set to the beginning
of the buffer of the stream and *sizeptr
should be set as follows:
*sizeptr = (qpstream->mode == QP_READ) ? 0 : qpstream->max_reclen;
The bottom layer seek function for our example stream:
static int bin_seek(qpstream, qpmagic, whence, bufptr, sizeptr) QP_stream *qpstream; union QP_cookie *qpmagic; int whence; unsigned char **bufptr; size_t *sizeptr; { BinStream *stream = CoerceBinStream(qpstream); off_t new_offset; switch (whence) { case QP_BEGINNING: new_offset = lseek(stream->fd,qpmagic->byteno,L_SET); break; case QP_CURRENT: /* The current location of file pointer is different from what the user thinks it is due to buffering. The magic field has been brought up to date by the caller of this function already, so just seek to that position first. */ if (lseek(stream->fd, qpstream->magic.byteno, L_SET) == -1) { qpstream->errno = errno; return QP_ERROR; } new_offset = lseek(stream->fd,qpmagic->byteno,L_INCR); break; case QP_END: new_offset = lseek(stream->fd,qpmagic->byteno,L_XTND); break; default: qpstream->errno = QP_E_INVAL; return QP_ERROR; } if (new_offset == -1) { /* error in seeking */ qpstream->errno = errno; return QP_ERROR; } qpstream->magic.byteno = new_offset; *bufptr = stream->buffer; *sizeptr = (qpstream->mode == QP_READ) ? 0 : qpstream->max_reclen; stream->last_rdsize = 0; return QP_SUCCESS; }