A stream's tt(read) member calls tt(xsgetn) to read tt(nChars) characters from
the device. The tt(nChar) characters might not be available in the current
buffer. In those cases tt(underflow) is called to refresh the
buffer. Initially some bytes may already be available. At each cycle the
number of available characters are copied to the next location of its tt(buf)
parameter, calling tt(underflow) if there are no available characters
anymore. So tt(xsgetn), while there are (still) characters to be read from the
device, must
    itemization(
    it() determine whether the current buffer contains available characters;
    it() if not, it must call tt(underflow);
    it() the number of available characters are copied to the next position of
        the tt(buf) parameter;
    it() the number of bytes to read is reduced by the number of available
        bytes; 
    it() the tt(buf) pointer and the counters are updated using the
        number of read bytes. 
    )

Here is a skeleton of tt(xsgetn):
    verbinclude(-a examples/xsgetn.cc)
