mxw_wotlk_azerothcore/deps/acelite/ace/IOStream.cpp

662 lines
18 KiB
C++

#ifndef ACE_IOSTREAM_CPP
#define ACE_IOSTREAM_CPP
#include "ace/IOStream.h"
#if !defined (ACE_LACKS_ACE_IOSTREAM)
# include "ace/OS_NS_errno.h"
# include "ace/OS_Memory.h"
///////////////////////////////////////////////////////////////////////////
/* Here's a simple example of how iostream's non-virtual operators can
get you in a mess:
class myiostream : public iostream
{
public:
myiostream& operator>> (String & s)
{
...
}
};
...
int i;
String s;
myiostream foo (...);
foo >> s;
// OK
// invokes myiostream::operator>> (String&) returning myiostream&
foo >> i;
// OK
// invokes iostream::operator>> (int&) returning iostream&
foo >> i >> s;
// BAD
// invokes iostream::operator>> (int&) then iostream::operator>> (String&)
//
// What has happened is that the first >> is invoked on the base class and returns
// a reference to iostream. The second >> has no idea of the ACE_IOStream and
// gets invoked on iostream. Probably NOT what you wanted!
// In order to make all of this work the way you want, you have to do this:
class myiostream : public iostream
{
public:
myiostream& operator>> (int & i)
{
return ((myiostream&)iostream::operator>> (i));
}
myiostream& operator>> (String & s)
{
...
}
};
...
int i;
String s;
myiostream foo (...);
foo >> s;
// OK
// invokes myiostream::operator>> (String&) returning myiostream&
foo >> i;
// OK
// invokes myiostream::operator>> (int&) returning myiostream&
foo >> i >> s;
// OK
// Because you provided operator>> (int&) in class myiostream, that
// function will be invoked by the first >>. Since it returns
// a myiostream&, the second >> will be invoked as desired. */
ACE_BEGIN_VERSIONED_NAMESPACE_DECL
ACE_HANDLE
ACE_Streambuf::get_handle (void)
{
return 0;
}
ACE_Time_Value *
ACE_Streambuf::recv_timeout (ACE_Time_Value *tv)
{
ACE_Time_Value * rval = recv_timeout_;
if (tv)
{
recv_timeout_value_ = *tv;
recv_timeout_ = &recv_timeout_value_;
}
else
recv_timeout_ = 0;
return rval;
}
int
ACE_Streambuf::underflow (void)
{
// If input mode is not set, any attempt to read from the stream is
// a failure.
if (ACE_BIT_DISABLED (mode_, ios::in))
return EOF;
// If base () is empty then this is the first time any get/put
// operation has been attempted on the stream.
if (!this->base ())
{
// Set base () to use our private read buffer. The arguments are:
// beginning of the buffer (base ())
// one-beyond the end of the buffer (ebase ())
// should base () be deleted on destruction
//
// We have to say "no" to the third parameter because we want to
// explicitly handle deletion of the TWO buffers at destruction.
setb (this->eback_saved_,
this->eback_saved_ + streambuf_size_, 0);
// Remember that we are now in getMode. This will help us if
// we're called prior to a mode change as well as helping us
// when the mode does change.
this->cur_mode_ = this->get_mode_;
// Using the new values for base (), initialize the get area.
// This simply sets eback (), gptr () and egptr () described
// earlier.
setg (base (), base (), base ());
// Set the put buffer such that puts will be disabled. Any
// attempt to put data will now cause overflow to be invoked.
setp (0, 0);
}
else // base () has been initialized already...
{
// If we are in put_mode_ now, then it is time to switch to get_mode_
//
// 1. get rid of any pending output
// 2. rearrange base () to use our half of the buffer
// 3. reset the mode
//
if (this->cur_mode_ == this->put_mode_)
{
// Dump any pending output to the peer. This is not really
// necessary because of the dual-buffer arrangement we've
// set up but intuitively it makes sense to send the pending
// data before we request data since the peer will probably
// need what we're sending before it can respond.
if (out_waiting () && syncout () == EOF)
return EOF;
if( ! pbase() )
{
delete [] pbase_saved_;
(void) reset_put_buffer();
}
else
{
// We're about to disable put mode but before we do
// that, we want to preserve it's state.
this->pbase_saved_ = pbase ();
this->pptr_saved_ = pptr ();
this->epptr_saved_ = epptr ();
}
// Disable put mode as described in the constructor.
setp (0, 0);
// Like the case where base () is false, we now point base
// () to use our private get buffer.
setb (this->eback_saved_,
this->eback_saved_ + streambuf_size_,
0);
// And restore the previous state of the get pointers.
setg (this->eback_saved_, this->gptr_saved_,
this->egptr_saved_);
// Finally, set our mode so that we don't get back into this
// if () and so that overflow can operate correctly.
cur_mode_ = get_mode_;
}
// There could be data in the input buffer if we switched to put
// mode before reading everything. In that case, we take this
// opportunity to feed it back to the iostream.
if (in_avail ())
// Remember that we return an int so that we can give back
// EOF. The explicit cast prevents us from returning a signed
// char when we're not returning EOF.
return (u_char) *gptr ();
}
// We really shouldn't be here unless there is a lack of data in the
// read buffer. So... go get some more data from the peer.
int result = fillbuf ();
// Fillbuf will give us EOF if there was an error with the peer. In
// that case, we can do no more input.
if (EOF == result)
{
// Disable ourselves and return failure to the iostream. That
// should result in a call to have oursleves closed.
setg (0, 0, 0);
return EOF;
}
// Return the next available character in the input buffer. Again,
// we protect against sign extension.
return (u_char) *gptr ();
}
// Much of this is similar to underflow. I'll just hit the highlights
// rather than repeating a lot of what you've already seen.
int
ACE_Streambuf::overflow (int c)
{
// Check to see if output is allowed at all.
if (! (mode_ & ios::out))
return EOF;
if (!base ())
{
// Set base () to use put's private buffer.
//
setb (this->pbase_saved_,
this->pbase_saved_ + streambuf_size_, 0);
// Set the mode for optimization.
this->cur_mode_ = this->put_mode_;
// Set the put area using the new base () values.
setp (base (), ebuf ());
// Disable the get area.
setg (0, 0, 0);
}
else // We're already reading or writing
{
// If we're coming out of get mode...
if (this->cur_mode_ == this->get_mode_)
{
// --> JCEJ 6/6/98
if (! eback())
{
/* Something has happened to cause the streambuf
to get rid of our get area.
We could probably do this a bit cleaner but
this method is sure to cleanup the bits and
pieces.
*/
delete [] eback_saved_;
(void) reset_get_buffer();
}
else
{
// Save the current get mode values
this->eback_saved_ = eback ();
this->gptr_saved_ = gptr ();
this->egptr_saved_ = egptr ();
}
// <-- JCEJ 6/6/98
// then disable the get buffer
setg (0, 0, 0);
// Reconfigure base () and restore the put pointers.
setb (pbase_saved_, pbase_saved_ + streambuf_size_, 0);
setp (base (), ebuf ());
// Save the new mode.
this->cur_mode_ = this->put_mode_;
}
// If there is output to be flushed, do so now. We shouldn't
// get here unless this is the case...
if (out_waiting () && EOF == syncout ())
return EOF;
}
// If we're not putting EOF, then we have to deal with the character
// that is being put. Perhaps we should do something special with EOF???
if (c != EOF)
{
// We've already written any data that may have been in the
// buffer, so we're guaranteed to have room in the buffer for
// this new information. So... we add it to the buffer and
// adjust our 'next' pointer acordingly.
*pptr () = (char) c;
pbump (1);
}
return 0;
}
// syncin
int
ACE_Streambuf::syncin (void)
{
// As discussed, there really isn't any way to sync input from a
// socket-like device. We specifially override this base-class
// function so that it won't do anything evil to us.
return 0;
}
// syncout
int
ACE_Streambuf::syncout (void)
{
// Unlike syncin, syncout is a doable thing. All we have to do is
// write whatever is in the output buffer to the peer. flushbuf ()
// is how we do it.
if (flushbuf () == EOF)
return EOF;
else
return 0;
}
int
ACE_Streambuf::sync (void)
{
// sync () is fairly traditional in that it syncs both input and
// output. We could have omitted the call to syncin () but someday,
// we may want it to do something.
syncin ();
// Don't bother syncing the output unless there is data to be
// sent...
if (out_waiting ())
return syncout ();
else
return 0;
}
// flushbuf
int
ACE_Streambuf::flushbuf (void)
{
// pptr () is one character beyond the last character put into the
// buffer. pbase () points to the beginning of the put buffer.
// Unless pptr () is greater than pbase () there is nothing to be
// sent to the peer.
if (pptr () <= pbase ())
return 0;
// 4/12/97 -- JCEJ
// Kludge!!!
// If the remote side shuts down the connection, an attempt to send
// () to the remote will result in the message 'Broken Pipe' I think
// this is an OS message, I've tracked it down to the ACE_OS::write
// () function. That's the last one to be called before the
// message. I can only test this on Linux though, so I don't know
// how other systems will react.
//
// To get around this gracefully, I do a PEEK recv () with an
// immediate (nearly) timeout. recv () is much more graceful on
// it's failure. If we get -1 from recv () not due to timeout then
// we know we're SOL.
//
// Q: Is 'errno' threadsafe? Should the section below be a
// critical section?
//
// char tbuf[1];
// ACE_Time_Value to (0,1);
// if (this->recv (tbuf, 1, MSG_PEEK, &to) == -1)
// {
// if (errno != ETIME)
// {
// perror ("OOPS preparing to send to peer");
// return EOF;
// }
// }
//
// The correct way to handle this is for the application to trap
// (and ignore?) SIGPIPE. Thanks to Amos Shapira for reminding me
// of this.
// Starting at the beginning of the buffer, send as much data as
// there is waiting. send guarantees that all of the data will be
// sent or an error will be returned.
if (this->send (pbase (), pptr () - pbase ()) == -1)
return EOF;
// Now that we've sent everything in the output buffer, we reset the
// buffer pointers to appear empty.
setp (base (), ebuf ());
return 0;
}
int
ACE_Streambuf::get_one_byte (void)
{
this->timeout_ = 0;
// The recv function will return immediately if there is no data
// waiting. So, we use recv_n to wait for exactly one byte to come
// from the peer. Later, we can use recv to see if there is
// anything else in the buffer. (Ok, we could use flags to tell it
// to block but I like this better.)
if (this->recv_n (base (), 1, MSG_PEEK, this->recv_timeout_) != 1)
{
if (errno == ETIME)
this->timeout_ = 1;
return EOF;
}
else
return 1;
}
// This will be called when the read (get) buffer has been exhausted
// (ie -- gptr == egptr).
int
ACE_Streambuf::fillbuf (void)
{
// Invoke recv_n to get exactly one byte from the remote. This will
// block until something shows up.
if (get_one_byte () == EOF)
return EOF;
// Now, get whatever else may be in the buffer. This will return if
// there is nothing in the buffer.
int bc = this->recv (base (), blen (), this->recv_timeout_);
// recv will give us -1 if there was a problem. If there was
// nothing waiting to be read, it will give us 0. That isn't an
// error.
if (bc < 0)
{
if (errno == ETIME)
this->timeout_ = 1;
return EOF;
}
// Move the get pointer to reflect the number of bytes we just read.
setg (base (), base (), base () + bc);
// Return the byte-read-count including the one from <get_one_byte>.
return bc;
}
ACE_Streambuf::ACE_Streambuf (u_int streambuf_size, int io_mode)
: eback_saved_ (0), // to avoid Purify UMR
pbase_saved_ (0), // to avoid Purify UMR
get_mode_ (1),
put_mode_ (2),
mode_ (io_mode),
streambuf_size_ (streambuf_size),
recv_timeout_ (0)
{
(void)reset_get_buffer ();
(void)reset_put_buffer ();
}
u_int
ACE_Streambuf::streambuf_size (void)
{
return streambuf_size_;
}
// Return the number of bytes not yet gotten. eback + get_waiting =
// gptr.
u_int
ACE_Streambuf::get_waiting (void)
{
return this->gptr_saved_ - this->eback_saved_;
}
// Return the number of bytes in the get area (includes some already
// gotten); eback + get_avail = egptr.
u_int
ACE_Streambuf::get_avail (void)
{
return this->egptr_saved_ - this->eback_saved_;
}
// Return the number of bytes to be 'put' onto the stream media.
// pbase + put_avail = pptr.
u_int
ACE_Streambuf::put_avail (void)
{
return this->pptr_saved_ - this->pbase_saved_;
}
// Typical usage:
//
// u_int newGptr = otherStream->get_waiting ();
// u_int newEgptr = otherStream->get_avail ();
// char * newBuf = otherStream->reset_get_buffer ();
// char * oldgetbuf = myStream->reset_get_buffer (newBuf, otherStream->streambuf_size (), newGptr, newEgptr);
//
// 'myStream' now has the get buffer of 'otherStream' and can use it in any way.
// 'otherStream' now has a new, empty get buffer.
char *
ACE_Streambuf::reset_get_buffer (char *newBuffer,
u_int _streambuf_size,
u_int _gptr,
u_int _egptr)
{
char * rval = this->eback_saved_;
// The get area is where the iostream will get data from. This is
// our read buffer. There are three pointers which describe the
// read buffer:
//
// eback () - The beginning of the buffer. Also the furthest
// point at which putbacks can be done. Hence the name.
//
// gptr () - Where the next character is to be got from.
//
// egptr () - One position beyond the last get-able character.
//
// So that we can switch quicky from read to write mode without
// any data copying, we keep copies of these three pointers in
// the variables below. Initially, they all point to the beginning
// of our read-dedicated buffer.
//
if (newBuffer)
{
if (streambuf_size_ != _streambuf_size)
return 0;
this->eback_saved_ = newBuffer;
}
else
ACE_NEW_RETURN (this->eback_saved_,
char[streambuf_size_],
0);
this->gptr_saved_ = this->eback_saved_ + _gptr;
this->egptr_saved_ = this->eback_saved_ + _egptr;
// Disable the get area initially. This will cause underflow to be
// invoked on the first get operation.
setg (0, 0, 0);
reset_base ();
return rval;
}
// Typical usage:
//
// u_int newPptr = otherStream->put_avail ();
// char * newBuf = otherStream->reset_put_buffer ();
// char * oldputbuf = otherStream->reset_put_buffer (newBuf, otherStream->streambuf_size (), newPptr);
char *
ACE_Streambuf::reset_put_buffer (char *newBuffer,
u_int _streambuf_size,
u_int _pptr)
{
char *rval = this->pbase_saved_;
// The put area is where the iostream will put data that needs to be
// sent to the peer. This becomes our write buffer. The three
// pointers which maintain this area are:
//
// pbase () - The beginning of the put area.
//
// pptr () - Where the next character is to be put.
//
// epptr () - One beyond the last valid position for putting.
//
// Again to switch quickly between modes, we keep copies of
// these three pointers.
//
if (newBuffer)
{
if (streambuf_size_ != _streambuf_size)
return 0;
this->pbase_saved_ = newBuffer;
}
else
ACE_NEW_RETURN (this->pbase_saved_,
char[streambuf_size_],
0);
this->pptr_saved_ = this->pbase_saved_ + _pptr;
this->epptr_saved_ = this->pbase_saved_ + streambuf_size_;
// Disable the put area. Overflow will be called by the first call
// to any put operator.
setp (0, 0);
reset_base ();
return rval;
}
void
ACE_Streambuf::reset_base (void)
{
// Until we experience the first get or put operation, we do not
// know what our current IO mode is.
this->cur_mode_ = 0;
// The common area used for reading and writting is called "base".
// We initialize it this way so that the first get/put operation
// will have to "allocate" base. This allocation will set base to
// the appropriate specific buffer and set the mode to the correct
// value.
setb (0, 0);
}
// If the default allocation strategey were used the common buffer
// would be deleted when the object destructs. Since we are providing
// separate read/write buffers, it is up to us to manage their memory.
ACE_Streambuf::~ACE_Streambuf (void)
{
delete [] this->eback_saved_;
delete [] this->pbase_saved_;
}
u_char ACE_Streambuf::timeout (void)
{
u_char rval = this->timeout_;
this->timeout_ = 0;
return rval;
}
ACE_END_VERSIONED_NAMESPACE_DECL
#endif /* !ACE_LACKS_ACE_IOSTREAM */
#endif /* ACE_IOSTREAM_CPP */