/* Portions Copyright 2003, QNX Software Systems Ltd. All Rights Reserved */

// sstream standard header
#ifndef _SSTREAM_
#define _SSTREAM_
#include <string>
_STD_BEGIN

		// CLASS stringbuf
class stringbuf
	: public streambuf
	{	// stream buffer maintaining an allocated character array
public:
	typedef char _Elem;
	typedef char_traits _Traits;
	typedef char_allocator allocator_type;
	typedef streambuf _Mysb;
	typedef string _Mystr;

	explicit stringbuf(ios_base::openmode _Mode =
		ios_base::in | ios_base::out)
		{	// construct empty character buffer from mode
		_Init(0, 0, _Getstate(_Mode));
		}

	explicit stringbuf(const _Mystr& _Str,
		ios_base::openmode _Mode = ios_base::in | ios_base::out)
		{	// construct character buffer from string, mode
		_Init(_Str.c_str(), _Str.size(), _Getstate(_Mode));
		}

	virtual ~stringbuf()
		{	// destroy the object
		_Tidy();
		}

	enum
		{	// constants for bits in stream state
		_Allocated = 1,	// set if character array storage has been allocated
		_Constant = 2,	// set if character array nonmutable
		_Noread = 4,	// set if character array cannot be read
		_Append = 8};	// set if all writes are appends
	typedef int _Strstate;

	typedef _Traits::int_type int_type;
	typedef _Traits::pos_type pos_type;
	typedef _Traits::off_type off_type;

	_Mystr str() const
		{	// return string copy of character array
		if (!(_Mystate & _Constant) && _Mysb::pptr() != 0)
			{	// writable, make string from write buffer
			_Mystr _Str(_Mysb::pbase(), (_Seekhigh < _Mysb::pptr()
				? _Mysb::pptr() : _Seekhigh) - _Mysb::pbase());
			return (_Str);
			}
		else if (!(_Mystate & _Noread) && _Mysb::gptr() != 0)
			{	// readable, make string from read buffer
			_Mystr _Str(_Mysb::eback(), _Mysb::egptr() - _Mysb::eback());
			return (_Str);
			}
		else
			{	// inaccessible, return empty string
			_Mystr _Nul;
			return (_Nul);
			}
		}

	void str(const _Mystr& _Newstr)
		{	// replace character array from string
		_Tidy();
		_Init(_Newstr.c_str(), _Newstr.size(), _Mystate);
		}

protected:
	virtual int_type overflow(int_type _Meta = _Traits::eof())
		{	// put an element to stream
		if (_Mystate & _Append
			&& _Mysb::pptr() != 0 && _Mysb::pptr() < _Seekhigh)
			_Mysb::setp(_Mysb::pbase(), _Seekhigh, _Mysb::epptr());

		if (_Traits::eq_int_type(_Traits::eof(), _Meta))
			return (_Traits::not_eof(_Meta));	// EOF, return success code
		else if (_Mysb::pptr() != 0
			&& _Mysb::pptr() < _Mysb::epptr())
			{	// room in buffer, store it
			*_Mysb::_Pninc() = _Traits::to_char_type(_Meta);
			return (_Meta);
			}
		else if (_Mystate & _Constant)
			return (_Traits::eof());	// array nonmutable, fail
		else
			{	// grow buffer and store element
			size_t _Oldsize = _Mysb::pptr() == 0
				? 0 : _Mysb::epptr() - _Mysb::eback();
			size_t _Newsize = _Oldsize;
			size_t _Inc = _Newsize / 2 < _MINSIZE
				? _MINSIZE : _Newsize / 2;	// grow by 50 per cent
			_Elem *_Ptr = 0;

			while (0 < _Inc && INT_MAX - _Inc < _Newsize)
				_Inc /= 2;	// increment causes overflow, halve it
			if (0 < _Inc)
				{	// finite increment, allocate new character array
				_Newsize += _Inc;
				_Ptr = _Al.allocate(_Newsize);
				}

			if (0 < _Oldsize)
				_Traits::copy(_Ptr, _Mysb::eback(), _Oldsize);
			if (_Mystate & _Allocated)
				_Al.deallocate(_Mysb::eback(), _Oldsize);
			_Mystate |= _Allocated;

			if (_Oldsize == 0)
				{	// first growth, set up pointers
				_Seekhigh = _Ptr;
				_Mysb::setp(_Ptr, _Ptr + _Newsize);
				if (_Mystate & _Noread)
					_Mysb::setg(_Ptr, 0, _Ptr);
				else
					_Mysb::setg(_Ptr, _Ptr, _Ptr + 1);
				}
			else
				{	// not first growth, adjust pointers
				_Seekhigh = _Seekhigh - _Mysb::eback() + _Ptr;
				_Mysb::setp(_Mysb::pbase() - _Mysb::eback() + _Ptr,
					_Mysb::pptr() - _Mysb::eback() + _Ptr, _Ptr + _Newsize);
				if (_Mystate & _Noread)
					_Mysb::setg(_Ptr, 0, _Ptr);
				else
					_Mysb::setg(_Ptr,
						_Mysb::gptr() - _Mysb::eback() + _Ptr,
						_Mysb::pptr() + 1);
				}

			*_Mysb::_Pninc() = _Traits::to_char_type(_Meta);
			return (_Meta);
			}
		}

	virtual int_type pbackfail(int_type _Meta = _Traits::eof())
		{	// put an element back to stream
		if (_Mysb::gptr() == 0
			|| _Mysb::gptr() <= _Mysb::eback()
			|| !_Traits::eq_int_type(_Traits::eof(), _Meta)
			&& !_Traits::eq(_Traits::to_char_type(_Meta), _Mysb::gptr()[-1])
			&& _Mystate & _Constant)
			return (_Traits::eof());	// can't put back, fail
		else
			{	// back up one position and store put-back character
			_Mysb::gbump(-1);
			if (!_Traits::eq_int_type(_Traits::eof(), _Meta))
				*_Mysb::gptr() = _Traits::to_char_type(_Meta);
			return (_Traits::not_eof(_Meta));
			}
		}

	virtual int_type underflow()
		{	// get an element from stream, but don't point past it
		if (_Mysb::gptr() == 0)
			return (_Traits::eof());	// no character buffer, fail
		else if (_Mysb::gptr() < _Mysb::egptr())
			return (_Traits::to_int_type(*_Mysb::gptr()));	// return buffered
		else if (_Mystate & _Noread || _Mysb::pptr() == 0
			|| _Mysb::pptr() <= _Mysb::gptr() && _Seekhigh <= _Mysb::gptr())
			return (_Traits::eof());	// can't read, fail
		else
			{	// extend read buffer into written area, then return buffered
			if (_Seekhigh < _Mysb::pptr())
				_Seekhigh = _Mysb::pptr();
			_Mysb::setg(_Mysb::eback(), _Mysb::gptr(), _Seekhigh);
			return (_Traits::to_int_type(*_Mysb::gptr()));
			}
		}

	virtual pos_type seekoff(off_type _Off,
		ios_base::seekdir _Way,
		ios_base::openmode _Which = ios_base::in | ios_base::out)
		{	// change position by _Off, according to _Way, _Mode
		if (_Mysb::pptr() != 0 && _Seekhigh < _Mysb::pptr())
			_Seekhigh = _Mysb::pptr();	// update high-water pointer

		if (_Which & ios_base::in && _Mysb::gptr() != 0)
			{	// position within read buffer
			if (_Way == ios_base::end)
				_Off += (off_type)(_Seekhigh - _Mysb::eback());
			else if (_Way == ios_base::cur
				&& (_Which & ios_base::out) == 0)
				_Off += (off_type)(_Mysb::gptr() - _Mysb::eback());
			else if (_Way != ios_base::beg)
				_Off = _BADOFF;

			if (0 <= _Off && _Off <= _Seekhigh - _Mysb::eback())
				{	// change read position
				_Mysb::gbump((int)(_Mysb::eback() - _Mysb::gptr() + _Off));
				if (_Which & ios_base::out && _Mysb::pptr() != 0)
					_Mysb::setp(_Mysb::pbase(), _Mysb::gptr(),
						_Mysb::epptr());	// change write position to match
				}
			else
				_Off = _BADOFF;
			}
		else if (_Which & ios_base::out && _Mysb::pptr() != 0)
			{	// position within write buffer
			if (_Way == ios_base::end)
				_Off += (off_type)(_Seekhigh - _Mysb::eback());
			else if (_Way == ios_base::cur)
				_Off += (off_type)(_Mysb::pptr() - _Mysb::eback());
			else if (_Way != ios_base::beg)
				_Off = _BADOFF;

			if (0 <= _Off && _Off <= _Seekhigh - _Mysb::eback())
				_Mysb::pbump((int)(_Mysb::eback()
					- _Mysb::pptr() + _Off));	// change write position
			else
				_Off = _BADOFF;
			}
		else
			_Off = _BADOFF;	// neither read nor write buffer selected, fail
		return (pos_type(_Off));
		}

	virtual pos_type seekpos(pos_type _Ptr,
		ios_base::openmode _Mode = ios_base::in | ios_base::out)
		{	// change position to _Pos, according to _Mode
		streamoff _Off = (streamoff)_Ptr;
		if (_Mysb::pptr() != 0 && _Seekhigh < _Mysb::pptr())
			_Seekhigh = _Mysb::pptr();	// update high-water pointer

		if (_Off == _BADOFF)
			;
		else if (_Mode & ios_base::in && _Mysb::gptr() != 0)
			{	// position within read buffer
			if (0 <= _Off && _Off <= _Seekhigh - _Mysb::eback())
				{	// change read position
				_Mysb::gbump((int)(_Mysb::eback() - _Mysb::gptr() + _Off));
				if (_Mode & ios_base::out && _Mysb::pptr() != 0)
					_Mysb::setp(_Mysb::pbase(), _Mysb::gptr(),
						_Mysb::epptr());	// change write position to match
				}
			else
				_Off = _BADOFF;
			}
		else if (_Mode & ios_base::out && _Mysb::pptr() != 0)
			{	// position within write buffer
			if (0 <= _Off && _Off <= _Seekhigh - _Mysb::eback())
				_Mysb::pbump((int)(_Mysb::eback()
					- _Mysb::pptr() + _Off));	// change write position
			else
				_Off = _BADOFF;
			}
		else
			_Off = _BADOFF;
		return (streampos(_Off));
		}

	void _Init(const _Elem *_Ptr,
		size_t _Count, _Strstate _State)
		{	// initialize buffer to [_Ptr, _Ptr + _Count), set state
		_Seekhigh = 0;
		_Mystate = _State;

		if (_Count != 0
			&& (_Mystate & (_Noread | _Constant)) != (_Noread | _Constant))
			{	// finite buffer that can be read or written, set it up
			_Elem *_Pnew = _Al.allocate(_Count);
			_Traits::copy(_Pnew, _Ptr, _Count);
			_Seekhigh = _Pnew + _Count;

			if (!(_Mystate & _Noread))
				_Mysb::setg(_Pnew, _Pnew,
					_Pnew + _Count);	// setup read buffer
			if (!(_Mystate & _Constant))
				{	// setup write buffer, and maybe read buffer
				_Mysb::setp(_Pnew, _Pnew + _Count);
				if (_Mysb::gptr() == 0)
					_Mysb::setg(_Pnew, 0, _Pnew);
				}
			_Mystate |= _Allocated;
			}
		}

	void _Tidy()
		{	// discard any allocated buffer and clear pointers
		if (_Mystate & _Allocated)
			_Al.deallocate(_Mysb::eback(),
				(_Mysb::pptr() != 0 ? _Mysb::epptr()
					: _Mysb::egptr()) - _Mysb::eback());
		_Mysb::setg(0, 0, 0);
		_Mysb::setp(0, 0);
		_Seekhigh = 0;
		_Mystate &= ~_Allocated;
		}

private:
	enum
		{	// constant for minimum buffer size
		_MINSIZE = 32};

	_Strstate _Getstate(ios_base::openmode _Mode)
		{	// convert open mode to stream state bits
		_Strstate _State = (_Strstate)0;
		if (!(_Mode & ios_base::in))
			_State |= _Noread;
		if (!(_Mode & ios_base::out))
			_State |= _Constant;
		if (_Mode & ios_base::app)
			_State |= _Append;
		return (_State);
		}

	_Elem *_Seekhigh;	// the high-water pointer in character array
	_Strstate _Mystate;	// the stream state
	allocator_type _Al;	// the allocator object
	};

		// CLASS istringstream
class istringstream
	: public istream
	{	// input stream associated with a character array
public:
	typedef char_traits _Traits;
	typedef stringbuf _Mysb;
	typedef string _Mystr;

	explicit istringstream(ios_base::openmode _Mode = ios_base::in)
		: istream(&_Stringbuffer), _Stringbuffer(_Mode | ios_base::in)
		{	// construct empty readable character buffer
		}

	explicit istringstream(const _Mystr& _Str,
		ios_base::openmode _Mode = ios_base::in)
		: istream(&_Stringbuffer), _Stringbuffer(_Str, _Mode | ios_base::in)
		{	// construct readable character buffer from NTBS
		}

	virtual ~istringstream()
		{	// destroy the object
		}

	_Mysb *rdbuf() const
		{	// return pointer to file buffer
		return ((_Mysb *)&_Stringbuffer);
		}

	_Mystr str() const
		{	// return string copy of character array
		return (_Stringbuffer.str());
		}

	void str(const _Mystr& _Newstr)
		{	// replace character array from string
		_Stringbuffer.str(_Newstr);
		}

private:
	_Mysb _Stringbuffer;	// the string buffer
	};

		// CLASS ostringstream
class ostringstream
	: public ostream
	{	// output stream associated with a character array
public:
	typedef char_traits _Traits;
	typedef stringbuf _Mysb;
	typedef string _Mystr;

	explicit ostringstream(ios_base::openmode _Mode = ios_base::out)
		: ostream(&_Stringbuffer), _Stringbuffer(_Mode | ios_base::out)
		{	// construct empty writable character buffer
		}

	explicit ostringstream(const _Mystr& _Str,
		ios_base::openmode _Mode = ios_base::out)
		: ostream(&_Stringbuffer),
			_Stringbuffer(_Str, _Mode | ios_base::out)
		{	// construct writable character buffer from NTBS
		}

	virtual ~ostringstream()
		{	// destroy the object
		}

	_Mysb *rdbuf() const
		{	// return pointer to buffer
		return ((_Mysb *)&_Stringbuffer);
		}

	_Mystr str() const
		{	// return string copy of character array
		return (_Stringbuffer.str());
		}

	void str(const _Mystr& _Newstr)
		{	// replace character array from string
		_Stringbuffer.str(_Newstr);
		}

private:
	_Mysb _Stringbuffer;	// the string buffer
	};

_STD_END
#endif /* _SSTREAM_ */

/*
 * Copyright (c) 1992-2003 by P.J. Plauger.  ALL RIGHTS RESERVED.
 * Consult your license regarding permissions and restrictions.
V4.02:1296 */
