Keeping track of the current offset is not a trivial problem. As long as
neither reading nor writing has been used tt(seekg) and tt(seekp) simply
compute the requested offset. Seek requests specifying tt(ios::beg) change
tt(offset) to the requested value. When tt(ios::end) is specified the offset
is computed relative to tt(getEnd) (since tt(getEnd) corresponds to the file
size of a physical disk-file tt(ios::end) should use tt(getEnd) as the current
end-offset and not tt(maxEnd)).

Computing offsets as shifts relative to the current offset is slightly
more complicated. When so far neither reading nor writing has been used
things are easy: the new offset equals the current offset plus the specified
tt(ios::off_type) sthift. But once information has just been read or written
things get complicated because tt(offset) doesn't correspond anymore to
the actual offset. 

For example, initially, when information is written to the device's tt(offset,
bufBeg) and tt(bufEnd) are computed so that tt(offset) is located inside the
buffer starting at tt(bufBegin) and continuing to tt(bufEnd), but thereafter
subsequent write requests are handled by the stream itself, and therefore
tt(offset) isn't updated. Instead only tt(pptr()'s) location, is updated,
invalidating tt(offset).

    Assume buffers are 100 bytes large, and in a concrete situation the buffer
covers the device's offsets 500 to 600 while tt(offset) equals 510. Then,
after writing tt("hello" pptr()) is 515, but tt(offset) is still at
510. Consequently, in that situation issuing tt(seekp(-5, ios::cur).tellp())
should not return 5 (i.e., tt(offset - 5)), but 10: tt(bufBegin + pptr() -
pbase() - 5). A similar situation is encountered when reading: tt(gptr()) is
updated by read operations.

This problem is solved by introducing three states: the tt(streambuf) object
starts in the tt(SEEK)-state: the last-used operation wasn't reading or
writing. Once reading is used the state changes to tt(READ), and to tt(WRITE)
once writing is used.

When s seek-request is issued the relative position depends on the current
state: in state tt(SEEK) the seek's shift value (as in tt(seekg(shift,
ios::cur)))is added to tt(offset), in state tt(READ) it's added to tt(bufBegin
+ gptr() - eback()), and in state tt(WRITE) it's added to tt(bufBegin + pptr()
- pbase()). Seek-requests also change the state to tt(SEEK), so subsequent
seek requests are computed relative to the last computed tt(offset). Finally,
to ensure that tt(underflow) and tt(overflow) are called when subsequent read
or write operations are requested seek requests also reset tt(setg) and
tt(setp) by calling them with 0 (zero) arguments. Here is a skeleton
implementation of tt(seekoff) (assuming tt(using namespace std)):
    verbinclude(-a examples/seekoff.cc)

