/* ** PJL C++ Library ** fdbuf.h ** ** Copyright (C) 2001 Paul J. Lucas ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ // standard #include #include #include // local #include "fdbuf.h" using namespace std; namespace PJL { //***************************************************************************** // // SYNOPSIS // void fdbuf::init( int fd ) // // DESCRIPTION // // Initialize an fdbuf. // //***************************************************************************** { fd_ = fd; setg( rbuf_, rbuf_ + buf_size, rbuf_ + buf_size ); setp( wbuf_, wbuf_ + buf_size ); } //***************************************************************************** // // SYNOPSIS // int fdbuf::sync() // // DESCRIPTION // // Synchronize the write buffer by writing it out. // // RETURN VALUE // // On success, returns 0; on failure, returns -1. // //***************************************************************************** { int const len = pptr() - pbase(); if ( write_buf( wbuf_, len ) != len ) return -1; pbump( -len ); return 0; } //***************************************************************************** // // SYNOPSIS // fdbuf::int_type fdbuf::overflow( int_type c ) // // DESCRIPTION // // This function is called when a single character is to be output. // // PARAMETERS // // c The single character to be stuffed into the buffer unless it is // EOF. // // RETURN VALUE // // On success, returns the passed-in character; on failure, returns EOF. // //***************************************************************************** { if ( sync() ) return EOF; if ( c != EOF ) { *pptr() = c; pbump( 1 ); } return c; } //***************************************************************************** // // SYNOPSIS // fdbuf::int_type fdbuf::underflow() // // DESCRIPTION // // This function is called when the buffer is underflowed, i.e., more // characters need to be read from the source. // // RETURN VALUE // // Returns the next character from the source or EOF on error. // //***************************************************************************** { if ( gptr() == egptr() ) { // // The get-pointer is at the end-pointer meaning that the read-buffer // is exhausted: read more. // ssize_t bytes; while ( true ) { if ( (bytes = ::read( fd_, rbuf_, buf_size )) > 0 ) { // // We read some bytes so stop. // break; } if ( bytes < 0 && (errno == EAGAIN || errno == EINTR) ) continue; return EOF; } setg( rbuf_, rbuf_, rbuf_ + bytes ); } return *gptr(); } //***************************************************************************** // // SYNOPSIS // streamsize fdbuf::write_buf( char const *buf, streamsize len ) // // DESCRIPTION // // Write a buffer to a Unix file descriptor. // // PARAMETERS // // buf The buffer to be written. // // len The length of the buffer. // // RETURN VALUE // // On success, returns the number of bytes written; on failure, returns // -1. // // SEE ALSO // // W. Richard Stevens. "Unix Network Programming, Vol 1, 2nd ed." // Prentice-Hall, Upper Saddle River, NJ, 1998. // //***************************************************************************** { streamsize total_bytes_written = 0; while ( true ) { ssize_t const bytes_written = ::write( fd_, buf, len ); if ( bytes_written >= 0 ) { // // Account for partial-writes in case the Unix file descriptor // happens to be attached to a socket. From [Stevens 1998], p. 77: // // Stream sockets (e.g., TCP sockets) exhibit a behavior with // the read and write functions that differs from normal file // I/O. A read or write on a stream socket might input or // output fewer bytes than requested, but this is not an error // condition. The reason is that buffer limits might be // reached for the kernel. All that is required is for the // caller to invoke the read or write function again, to input // or output the remaining bytes. // // Note that if the file descriptor isn't attached to a socket, the // entire buffer will be written, so the loop will exit. // total_bytes_written += bytes_written; if ( bytes_written == len ) return total_bytes_written; len -= bytes_written; buf += bytes_written; continue; } if ( errno == EINTR ) // interrupt-proof continue; return -1; } } //***************************************************************************** // // SYNOPSIS // streamsize fdbuf::xsputn( char const *buf, streamsize len ) // // DESCRIPTION // // This function is called to output an entire buffer (as opposed to a // single character). // // RETURN VALUE // // On success, returns the number of bytes written; on failure, returns // -1. // //***************************************************************************** { if ( epptr() - pptr() >= len ) { // // The contents of buf will fit into the existing put-buffer so just // put it there. // ::memcpy( pptr(), buf, len ); pbump( len ); return len; } // // The contents of buf will not fit into the existing put-buffer so // syncronize what's currently there then write out the contents of buf // directly. // return sync() ? -1 : write_buf( buf, len ); } } // namespace PJL /* vim:set et sw=4 ts=4: */