text: // $Id: IOStream.cpp 93359 2011-02-11 11:33:12Z mcorino $
  
  #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 */
  