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; }
int filebuf::xsputn(const char *s, int n) { if (n <= 0) return 0; // This is an optimized implementation. // If the amount to be written straddles a block boundary // (or the filebuf is unbuffered), use sys_write directly. int to_do = n; int must_flush = 0; // First figure out how much space is available in the buffer. int count = _epptr - _pptr; // Space available. if (linebuffered() && (_flags & _S_CURRENTLY_PUTTING)) { count =_ebuf - _pptr; if (count >= n) { for (register const char *p = s + n; p > s; ) { if (*--p == '\n') { count = p - s + 1; must_flush = 1; break; } } } } // Then fill the buffer. if (count > 0) { if (count > to_do) count = to_do; if (count > 20) { memcpy(pptr(), s, count); s += count; } else { register char *p = pptr();; for (register int i = count; --i >= 0; ) *p++ = *s++; } pbump(count); to_do -= count; } if (to_do + must_flush > 0) { // Next flush the (full) buffer. if (__overflow(this, EOF) == EOF) return n - to_do; // Try to maintain alignment: write a whole number of blocks. // dont_write is what gets left over. int block_size = _ebuf - _base; int dont_write = block_size >= 128 ? to_do % block_size : 0; _G_ssize_t count = to_do - dont_write; if (do_write(s, count) == EOF) return n - to_do; to_do = dont_write; // Now write out the remainder. Normally, this will fit in the // buffer, but it's somewhat messier for line-buffered files, // so we let streambuf::xsputn handle the general case. if (dont_write) to_do -= streambuf::xsputn(s+count, dont_write); } return n - to_do; }