int filebuf::do_write(const char *data, int to_do) { if (to_do == 0) return 0; if (xflags() & _S_IS_APPENDING) { // On a system without a proper O_APPEND implementation, // you would need to sys_seek(0, ios::end) here, but is // is not needed nor desirable for Unix- or Posix-like systems. // Instead, just indicate that offset (before and after) is // unpredictable. _fb._offset = -1; } else if (egptr() != pbase()) { long new_pos = sys_seek(pbase()-egptr(), ios::cur); if (new_pos == -1) return EOF; _fb._offset = new_pos; } _G_ssize_t count = sys_write(data, to_do); if (_cur_column) _cur_column = __adjust_column(_cur_column - 1, data, to_do) + 1; setg(base(), base(), base()); if (xflags() & _S_LINE_BUF+_S_UNBUFFERED) setp(base(), base()); else setp(base(), ebuf()); return count != to_do ? EOF : 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; }
filebuf::~filebuf() { if (!(xflags() & _S_DELETE_DONT_CLOSE)) close(); _un_link(); }
int filebuf::underflow() { #if 0 /* SysV does not make this test; take it out for compatibility */ if (fp->_flags & __SEOF) return (EOF); #endif if (xflags() & _S_NO_READS) return EOF; if (gptr() < egptr()) return *(unsigned char*)gptr(); allocbuf(); // FIXME This can/should be moved to __streambuf ?? if ((xflags() & _S_LINE_BUF) || unbuffered()) { // Flush all line buffered files before reading. streambuf::flush_all_linebuffered(); } #if 1 if (pptr() > pbase()) if (do_flush()) return EOF; #endif _G_ssize_t count = sys_read(base(), ebuf() - base()); if (count <= 0) { if (count == 0) xsetflags(_S_EOF_SEEN); else xsetflags(_S_ERR_SEEN), count = 0; } setg(base(), base(), base() + count); setp(base(), base()); if (count == 0) return EOF; if (_fb._offset >= 0) _fb._offset += count; return *(unsigned char*)gptr(); }
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; }