The Bottom Layer Seek Function
     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)

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