// -*- C++ -*- //============================================================================= /** * @file IOStream.h * * @author James CE Johnson * @author Jim Crossley */ //============================================================================= #ifndef ACE_IOSTREAM_H #define ACE_IOSTREAM_H #include /**/ "ace/pre.h" #include /**/ "ace/ACE_export.h" #if !defined (ACE_LACKS_PRAGMA_ONCE) # pragma once #endif /* ACE_LACKS_PRAGMA_ONCE */ // Needed on Windows for streambuf // FUZZ: disable check_for_streams_include #include "ace/streams.h" // This is a temporary restriction - ACE_IOStream is only enabled if the // compiler does not supply the standard C++ library (and standard iostreams) // or, if it does, the platform is explicitly set to use old iostreams // by its config.h file. // This restriction is recorded in Bugzilla entry 857. #if !defined (ACE_USES_OLD_IOSTREAMS) && !defined (ACE_LACKS_ACE_IOSTREAM) # define ACE_LACKS_ACE_IOSTREAM #endif /* !ACE_USES_OLD_IOSTREAMS && !ACE_LACKS_ACE_IOSTREAM */ #if !defined (ACE_LACKS_ACE_IOSTREAM) # include /**/ ACE_BEGIN_VERSIONED_NAMESPACE_DECL typedef std::string ACE_IOStream_String; ACE_END_VERSIONED_NAMESPACE_DECL ACE_BEGIN_VERSIONED_NAMESPACE_DECL class ACE_Export ACE_Quoted_String : public ACE_IOStream_String { public: inline ACE_Quoted_String () { *this = ""; } inline ACE_Quoted_String (const char *c) { *this = ACE_IOStream_String (c); } inline ACE_Quoted_String (const ACE_IOStream_String &s) { *this = s; } inline ACE_Quoted_String &operator= (const ACE_IOStream_String& s) { return (ACE_Quoted_String &) ACE_IOStream_String::operator= (s); } inline ACE_Quoted_String &operator = (const char c) { return (ACE_Quoted_String &) ACE_IOStream_String::operator= (c); } inline ACE_Quoted_String &operator = (const char *c) { return (ACE_Quoted_String &) ACE_IOStream_String::operator= (c); } inline bool operator < (const ACE_Quoted_String &s) const { return *(ACE_IOStream_String *) this < (ACE_IOStream_String) s; } # if defined (ACE_WIN32) && defined (_MSC_VER) inline int length () { return this->GetLength (); } # endif /* ACE_WIN32 && defined (_MSC_VER) */ }; ACE_END_VERSIONED_NAMESPACE_DECL # include "ace/Time_Value.h" # include "ace/os_include/sys/os_types.h" ACE_BEGIN_VERSIONED_NAMESPACE_DECL /** * @class ACE_Streambuf * * @brief Create your custom streambuf by providing and ACE_*_Stream * object to this template. I have tested it with * ACE_SOCK_Stream and it should work fine for others as well. * * For any iostream object, the real work is done by the * underlying streambuf class. That is what we create here. * A streambuf has an internal buffer area into which data is * read and written as the iostream requests and provides data. * At some point during the read process, the iostream will * realize that the streambuf has no more data. The underflow * function of the streambuf is then called. * Likewise, during the write process, the iostream will * eventually notice that the streabuf's buffer has become full * and will invoke the overflow function. * The empty/full state of the read/write "buffers" are * controled by two sets pointers. One set is dedicated to * read, the other to write. These pointers, in turn, reference * a common buffer that is to be shared by both read and write * operations. It is this common buffer to which data is * written and from which it is read. * The common buffer is used by functions of the streambuf as * well as the iostream. Because of this and the fact that it * is "shared" by both read and write operators, there is a * danger of data corruption if read and write operations are * allowed to take place "at the same time". * To prevent data corruption, we manipulate the read and write * pointer sets so that the streambuf is in either a read-mode * or write-mode at all times and can never be in both modes at * the same time. * In the constructor: set the read and write sets to NULL This * causes the underflow or overflow operators to be invoked at * the first IO activity of the iostream. * In the underflow function we arrange for the common buffer to * reference our read buffer and for the write pointer set to be * disabled. If a write operation is performed by the iostream * this will cause the overflow function to be invoked. * In the overflow function we arrange for the common buffer to * reference our write buffer and for the read pointer set to be * disabled. This causes the underflow function to be invoked * when the iostream "changes our mode". * The overflow function will also invoke the send_n function to * flush the buffered data to our peer. Similarly, the sync and * syncout functions will cause send_n to be invoked to send the * data. * Since socket's and the like do not support seeking, there can * be no method for "syncing" the input. However, since we * maintain separate read/write buffers, no data is lost by * "syncing" the input. It simply remains buffered. */ class ACE_Export ACE_Streambuf : public streambuf { public: /** * If the default allocation strategy 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. */ virtual ~ACE_Streambuf (); /// Get the current Time_Value pointer and provide a new one. ACE_Time_Value *recv_timeout (ACE_Time_Value *tv = 0); /** * Use this to allocate a new/different buffer for put operations. * If you do not provide a buffer pointer, one will be allocated. * That is the preferred method. If you do provide a buffer, the * size must match that being used by the get buffer. If * successful, you will receive a pointer to the current put buffer. * It is your responsibility to delete this memory when you are done * with it. */ char *reset_put_buffer (char *newBuffer = 0, u_int _streambuf_size = 0, u_int _pptr = 0 ); /// Return the number of bytes to be 'put' onto the stream media. /// pbase + put_avail = pptr u_int put_avail (); /** * Use this to allocate a new/different buffer for get operations. * If you do not provide a buffer pointer, one will be allocated. * That is the preferred method. If you do provide a buffer, the * size must match that being used by the put buffer. If * successful, you will receive a pointer to the current get buffer. * It is your responsibility to delete this memory when you are done * with it. */ char *reset_get_buffer (char *newBuffer = 0, u_int _streambuf_size = 0, u_int _gptr = 0, u_int _egptr = 0); /// Return the number of bytes not yet gotten. eback + get_waiting = /// gptr u_int get_waiting (); /// Return the number of bytes in the get area (includes some already /// gotten); eback + get_avail = egptr u_int get_avail (); /// Query the streambuf for the size of its buffers. u_int streambuf_size (); /// Did we take an error because of an IO operation timeout? /// @note Invoking this resets the flag. u_char timeout (); protected: ACE_Streambuf (u_int streambuf_size, int io_mode); /// Sync both input and output. See syncin/syncout below for /// descriptions. virtual int sync (); // = Signatures for the underflow/overflow discussed above. virtual int underflow (); /// The overflow function receives the character which caused the /// overflow. virtual int overflow (int c = EOF); /// Resets the pointer and streambuf mode. This is used /// internally when get/put buffers are allocatd. void reset_base (); protected: // = Two pointer sets for manipulating the read/write areas. char *eback_saved_; char *gptr_saved_; char *egptr_saved_; char *pbase_saved_; char *pptr_saved_; char *epptr_saved_; // = With cur_mode_ we keep track of our current IO mode. // This helps us to optimize the underflow/overflow functions. u_char cur_mode_; const u_char get_mode_; const u_char put_mode_; /// mode tells us if we're working for an istream, ostream, or /// iostream. int mode_; /// This defines the size of the input and output buffers. It can be /// set by the object constructor. const u_int streambuf_size_; /// Did we take an error because of an IO operation timeout? u_char timeout_; /// We want to allow the user to provide Time_Value pointers to /// prevent infinite blocking while waiting to receive data. ACE_Time_Value recv_timeout_value_; ACE_Time_Value *recv_timeout_; /** * syncin is called when the input needs to be synced with the * source file. In a filebuf, this results in the system * call being used. We can't do that on socket-like connections, so * this does basically nothing. That's safe because we have a * separate read buffer to maintain the already-read data. In a * filebuf, the single common buffer is used forcing the * call. */ int syncin (); /// syncout() is called when the output needs to be flushed. This is /// easily done by calling the peer's send_n function. int syncout (); /// flushbuf() is the worker of syncout. It is a separate function /// because it gets used sometimes in different context. int flushbuf (); /** * fillbuf is called in a couple of places. This is the worker of * underflow. It will attempt to fill the read buffer from the * peer. */ int fillbuf (); /** * Used by fillbuf and others to get exactly one byte from the peer. * recv_n is used to be sure we block until something is available. * It is virtual because we really need to override it for * datagram-derived objects. */ virtual int get_one_byte (); /** * Stream connections and "unconnected connections" (ie -- * datagrams) need to work just a little differently. We derive * custom Streambuf objects for them and provide these functions at * that time. */ virtual ssize_t send (char *buf, ssize_t len) = 0; virtual ssize_t recv (char *buf, ssize_t len, ACE_Time_Value *tv = 0) = 0; virtual ssize_t recv (char *buf, ssize_t len, int flags, ACE_Time_Value *tv = 0) = 0; virtual ssize_t recv_n (char *buf, ssize_t len, int flags = 0, ACE_Time_Value *tv = 0) = 0; virtual ACE_HANDLE get_handle (); # if !defined (ACE_USES_OLD_IOSTREAMS) char *base () const { return cur_mode_ == get_mode_ ? eback_saved_ : cur_mode_ == put_mode_ ? pbase_saved_ : 0; } char *ebuf () const { return cur_mode_ == 0 ? 0 : base () + streambuf_size_; } int blen () const { return streambuf_size_; } void setb (char* b, char* eb, int /* a */=0) { setbuf (b, (eb - b)); } int out_waiting () { return pptr () - pbase (); } # endif /* !ACE_USES_OLD_IOSTREAMS */ }; ACE_END_VERSIONED_NAMESPACE_DECL /////////////////////////////////////////////////////////////////////////// // These typedefs are provided by G++ (on some systems?) without the // trailing '_'. Since we can't count on 'em, I've defined them to // what GNU wants here. // typedef ios& (*__manip_)(ios&); typedef istream& (*__imanip_)(istream&); typedef ostream& (*__omanip_)(ostream&); // Trying to do something like is shown below instead of using the // __*manip typedefs causes Linux do segfault when "< and functions are used. #define GET_SIG(MT,DT) inline virtual MT& operator>> (DT v) #define GET_CODE { \ if (ipfx (0)) \ { \ iostream::operator>> (v); \ } \ isfx (); \ return *this; \ } #define GET_PROT(MT,DT,CODE) GET_SIG(MT,DT) CODE #define GET_FUNC(MT,DT) GET_PROT(MT,DT,GET_CODE) // This macro defines the put operator for class MT into datatype DT. // We will use it below to quickly override most (all?) iostream put // operators. Notice how the and functions are used. #define PUT_SIG(MT,DT) inline virtual MT& operator<< (DT v) #define PUT_CODE { \ if (opfx ()) \ { \ iostream::operator<< (v); \ } \ osfx (); \ return *this; \ } #define PUT_PROT(MT,DT,CODE) PUT_SIG(MT,DT) CODE #define PUT_FUNC(MT,DT) PUT_PROT(MT,DT,PUT_CODE) // These are necessary in case somebody wants to derive from us and // override one of these with a custom approach. #define GET_FUNC_SET0(MT,CODE,CODE2) \ GET_PROT(MT,short &,CODE) \ GET_PROT(MT,u_short &,CODE) \ GET_PROT(MT,int &,CODE) \ GET_PROT(MT,u_int &,CODE) \ GET_PROT(MT,long &,CODE) \ GET_PROT(MT,u_long &,CODE) \ GET_PROT(MT,float &,CODE) \ GET_PROT(MT,double &,CODE) \ GET_PROT(MT,char &,CODE) \ GET_PROT(MT,u_char &,CODE) \ GET_PROT(MT,char *,CODE) \ GET_PROT(MT,u_char *,CODE) \ inline virtual MT& operator>>(__omanip_ func) CODE2 \ inline virtual MT& operator>>(__manip_ func) CODE2 #define PUT_FUNC_SET0(MT,CODE,CODE2) \ PUT_PROT(MT,short,CODE) \ PUT_PROT(MT,u_short,CODE) \ PUT_PROT(MT,int,CODE) \ PUT_PROT(MT,u_int,CODE) \ PUT_PROT(MT,long,CODE) \ PUT_PROT(MT,u_long,CODE) \ PUT_PROT(MT,float,CODE) \ PUT_PROT(MT,double,CODE) \ PUT_PROT(MT,char,CODE) \ PUT_PROT(MT,u_char,CODE) \ PUT_PROT(MT,const char *,CODE) \ PUT_PROT(MT,u_char *,CODE) \ PUT_PROT(MT,void *,CODE) \ inline virtual MT& operator<<(__omanip_ func) CODE2 \ inline virtual MT& operator<<(__manip_ func) CODE2 #define GET_FUNC_SET1(MT,CODE,CODE2) \ GET_PROT(MT,signed char &,CODE) \ GET_PROT(MT,signed char *,CODE) \ GET_FUNC_SET0(MT,CODE,CODE2) #define PUT_FUNC_SET1(MT,CODE,CODE2) \ PUT_FUNC(MT,signed char) \ PUT_FUNC(MT,const signed char *) \ PUT_FUNC_SET0(MT,CODE,CODE2) #define GET_MANIP_CODE { if (ipfx ()) { (*func) (*this); } isfx (); return *this; } #define PUT_MANIP_CODE { if (opfx ()) { (*func) (*this); } osfx (); return *this; } #define GET_FUNC_SET(MT) GET_FUNC_SET1(MT,GET_CODE,GET_MANIP_CODE) #define PUT_FUNC_SET(MT) PUT_FUNC_SET1(MT,PUT_CODE,PUT_MANIP_CODE) #define GETPUT_FUNC_SET(MT) GET_FUNC_SET(MT) PUT_FUNC_SET(MT) #define GET_SIG_SET(MT) GET_FUNC_SET1(MT,= 0;,= 0;) #define PUT_SIG_SET(MT) PUT_FUNC_SET1(MT,= 0;,= 0;) #define GETPUT_SIG_SET(MT) GET_SIG_SET(MT) PUT_SIG_SET(MT) // Include the templates here. # include "ace/IOStream_T.h" #endif /* !ACE_LACKS_ACE_IOSTREAM && ACE_USES_OLD_IOSTREAMS */ #include /**/ "ace/post.h" #endif /* ACE_IOSTREAM_H */