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