Ejemplo n.º 1
0
int filebuf::overflow(int c)
{
    if (xflags() & _S_NO_WRITES) // SET ERROR
	return EOF;
    // Allocate a buffer if needed.
    if (base() == NULL) {
	doallocbuf();
	if (xflags() & _S_LINE_BUF+_S_UNBUFFERED) setp(_base, _base);
	else setp(_base, _ebuf);
	setg(_base, _base, _base);
	_flags |= _S_CURRENTLY_PUTTING;
    }
    // If currently reading, switch to writing.
    else if ((_flags & _S_CURRENTLY_PUTTING) == 0) {
	if (xflags() & _S_LINE_BUF+_S_UNBUFFERED) setp(gptr(), gptr());
	else setp(gptr(), ebuf());
	setg(egptr(), egptr(), egptr());
	_flags |= _S_CURRENTLY_PUTTING;
    }
    if (c == EOF)
	return do_flush();
    if (pptr() == ebuf() ) // Buffer is really full
	if (do_flush() == EOF)
	    return EOF;
    xput_char(c);
    if (unbuffered() || (linebuffered() && c == '\n'))
	if (do_flush() == EOF)
	    return EOF;
    return (unsigned char)c;
}
Ejemplo n.º 2
0
streampos filebuf::seekoff(streamoff offset, _seek_dir dir, int mode)
{
    streampos result, new_offset, delta;
    _G_ssize_t count;

    if (mode == 0) // Don't move any pointers.
	dir = ios::cur, offset = 0;

    // Flush unwritten characters.
    // (This may do an unneeded write if we seek within the buffer.
    // But to be able to switch to reading, we would need to set
    // egptr to ptr.  That can't be done in the current design,
    // which assumes file_ptr() is eGptr.  Anyway, since we probably
    // end up flushing when we close(), it doesn't make much difference.)
    if (pptr() > pbase() || put_mode())
	if (switch_to_get_mode()) return EOF;

    if (base() == NULL) {
	doallocbuf();
	setp(base(), base());
	setg(base(), base(), base());
    }
    switch (dir) {
      case ios::cur:
	if (_fb._offset < 0) {
	    _fb._offset = sys_seek(0, ios::cur);
	    if (_fb._offset < 0)
		return EOF;
	}
	// Make offset absolute, assuming current pointer is file_ptr().
	offset += _fb._offset;

	offset -= _egptr - _gptr;
	if (in_backup())
	    offset -= _other_egptr - _other_gbase;
	dir = ios::beg;
	break;
      case ios::beg:
	break;
      case ios::end:
	struct stat st;
	if (sys_stat(&st) == 0 && S_ISREG(st.st_mode)) {
	    offset += st.st_size;
	    dir = ios::beg;
	}
	else
	    goto dumb;
    }
    // At this point, dir==ios::beg.

    // If destination is within current buffer, optimize:
    if (_fb._offset >= 0 && _eback != NULL) {
	// Offset relative to start of main get area.
	fpos_t rel_offset = offset - _fb._offset
	    + (eGptr()-Gbase());
	if (rel_offset >= 0) {
	    if (in_backup())
		switch_to_main_get_area();
	    if (rel_offset <= _egptr - _eback) {
		setg(base(), base() + rel_offset, egptr());
		setp(base(), base());
		return offset;
	    }
	    // If we have streammarkers, seek forward by reading ahead.
	    if (have_markers()) {
		int to_skip = rel_offset - (_gptr - _eback);
		if (ignore(to_skip) != to_skip)
		    goto dumb;
		return offset;
	    }
	}
	if (rel_offset < 0 && rel_offset >= Bbase() - Bptr()) {
	    if (!in_backup())
		switch_to_backup_area();
	    gbump(_egptr + rel_offset - gptr());
	    return offset;
	}
    }

    unsave_markers();

    // Try to seek to a block boundary, to improve kernel page management.
    new_offset = offset & ~(ebuf() - base() - 1);
    delta = offset - new_offset;
    if (delta > ebuf() - base()) {
	new_offset = offset;
	delta = 0;
    }
    result = sys_seek(new_offset, ios::beg);
    if (result < 0)
	return EOF;
    if (delta == 0)
	count = 0;
    else {
	count = sys_read(base(), ebuf()-base());
	if (count < delta) {
	    // We weren't allowed to read, but try to seek the remainder.
	    offset = count == EOF ? delta : delta-count;
	    dir = ios::cur;
	    goto dumb;
	}
    }
    setg(base(), base()+delta, base()+count);
    setp(base(), base());
    _fb._offset = result + count;
    xflags(xflags() & ~ _S_EOF_SEEN);
    return offset;
  dumb:
    unsave_markers();
    result = sys_seek(offset, dir);
    if (result != EOF) {
	xflags(xflags() & ~_S_EOF_SEEN);
    }
    _fb._offset = result;
    setg(base(), base(), base());
    setp(base(), base());
    return result;
}