// strstreambuf -- strstreambuf basic members
#include <climits>
#include <cstdlib>
#include <cstring>
#include <strstream>
#include <xdebug>
_STD_BEGIN

istrstream::~istrstream()
	{	// destroy an istrstream
	}

ostrstream::ostrstream(char *ptr, streamsize count,
	ios_base::openmode mode)
	: ostream(&_Mysb),
	_Mysb(ptr, count, ptr == 0 || (mode & ios_base::app) == 0
		? ptr : ptr + strlen(ptr))
	{	// construct with [ptr, ptr + count)
	}

ostrstream::~ostrstream()
	{	// destroy an ostrstream
	}

 #if _IS_EMBEDDED

 #else /* _IS_EMBEDDED */

strstream::strstream(char *ptr, streamsize count,
	ios_base::openmode mode)
	: iostream(&_Mysb),
	_Mysb(ptr, count, ptr == 0 || (mode & ios_base::app) == 0
		? ptr : ptr + strlen(ptr))
	{	// construct with [ptr, ptr + count)
	}

strstream::~strstream()
	{	// destroy a strstream
	}
 #endif /* _IS_EMBEDDED */

strstreambuf::~strstreambuf()
	{	// destroy a strstreambuf
	_Tidy();
	}

void strstreambuf::freeze(bool freezeit)
	{	// freeze or unfreeze writing
	if (freezeit && !(_Strmode & _Frozen))
		{	// disable writing
		_Strmode |= _Frozen;
		_Pendsave = epptr();
		setp(pbase(), pptr(), eback());
		}
	else if (!freezeit && _Strmode & _Frozen)
		{	// re-enable writing
		_Strmode &= ~_Frozen;
		setp(pbase(), pptr(), _Pendsave);
		}
	}

int strstreambuf::overflow(int meta)
	{	// try to extend write area
	if (meta == EOF)
		return (0);	// nothing to write
	else if (pptr() != 0 && pptr() < epptr())
		return ((unsigned char)(*_Pninc() = meta));	// room in buffer
	else if (!(_Strmode & _Dynamic)
		|| _Strmode & (_Constant | _Frozen))
		return (EOF);	// can't extend
	else
		{	// okay to extend
		int oldsize = gptr() == 0 ? 0 : epptr() - eback();
		int newsize = oldsize;
		int inc = newsize / 2 < _Minsize
			? _Minsize : newsize / 2;	// grow by 50 per cent if possible
		_Minsize = _MINSIZE;	// back to default for future growth
		char *ptr = 0;

		while (0 < inc && INT_MAX - inc < newsize)
			inc /= 2;	// reduce growth increment if too big
		if (0 < inc)
			{	// room to grow, increase size
			newsize += inc;
			ptr = _Palloc != 0 ? (char *)(*_Palloc)(newsize)
				: _NEW_CRT char[newsize];
			}
		if (ptr == 0)
			return (EOF);	// couldn't grow, return failure

		if (0 < oldsize)
			memcpy(ptr, eback(), oldsize);	// copy existing buffer
		if (!(_Strmode & _Allocated))
			;	// no buffer to free
		else if (_Pfree != 0)
			(*_Pfree)(eback());	// free with function call
		else
			_DELETE_CRT_VEC(eback());	// free by deleting array

		_Strmode |= _Allocated;
		if (oldsize == 0)
			{	// set up new buffer
			_Seekhigh = ptr;
			setp(ptr, ptr + newsize);
			setg(ptr, ptr, ptr);
			}
		else
			{	// revise old pointers
			_Seekhigh = _Seekhigh - eback() + ptr;
			setp(pbase() - eback() + ptr, pptr() - eback() + ptr,
				ptr + newsize);
			setg(ptr, gptr() - eback() + ptr, pptr() + 1);
			}

		return ((unsigned char)(*_Pninc() = meta));
		}
	}

int strstreambuf::pbackfail(int meta)
	{	// try to putback a character
	if (gptr() == 0 || gptr() <= eback() || meta != EOF
			&& (unsigned char)meta != (unsigned char)gptr()[-1]
			&& _Strmode & _Constant)
		return (EOF);	// can't put it back
	else
		{	// safe to back up
		gbump(-1);
		return (meta == EOF ? 0 : (unsigned char)(*gptr() = meta));
		}
	}

int strstreambuf::underflow()
	{	// read if read position available
	if (gptr() == 0)
		return (EOF);	// no read buffer
	else if (gptr() < egptr())
		return ((unsigned char)*gptr());	// char in buffer, read it
	else if (pptr() == 0 || pptr() <= gptr() && _Seekhigh <= gptr())
		return (EOF);	// no write buffer to read
	else
		{	// update _Seekhigh and expand read region
		if (_Seekhigh < pptr())
			_Seekhigh = pptr();
		setg(eback(), gptr(), _Seekhigh);
		return ((unsigned char)*gptr());
		}
	}

streampos strstreambuf::seekoff(streamoff off,
	ios_base::seekdir way, ios_base::openmode which)
	{	// seek by specified offset
	if (pptr() != 0 && _Seekhigh < pptr())
		_Seekhigh = pptr();	// update high water mark

	if (which & ios_base::in && gptr() != 0)
		{	// set input (and maybe output) pointer
		if (way == ios_base::end)
			off += _Seekhigh - eback();	// seek from end
		else if (way == ios_base::cur
			&& !(which & ios_base::out))
			off += gptr() - eback();	// seek from current position
		else if (way != ios_base::beg || off == _BADOFF)
			off = _BADOFF;	// invalid seek
		if (0 <= off && off <= _Seekhigh - eback())
			{	// seek from beginning, set one or two pointers
			gbump(eback() - gptr() + off);
			if (which & ios_base::out && pptr() != 0)
				setp(pbase(), gptr(), epptr());
			}
		else
			off = _BADOFF;	// invalid seek from beginning
		}
	else if (which & ios_base::out && pptr() != 0)
		{	// set only output pointer
		if (way == ios_base::end)
			off += _Seekhigh - eback();	// seek from end
		else if (way == ios_base::cur)
			off += pptr() - eback();	// seek from current position
		else if (way != ios_base::beg || off == _BADOFF)
			off = _BADOFF;	// invalid seek
		if (0 <= off && off <= _Seekhigh - eback())
			pbump(eback() - pptr() + off);	// seek from beginning
		else
			off = _BADOFF;	// invalid seek from beginning
		}
	else	// nothing to set
		off = _BADOFF;
	return (streampos(off));
	}

streampos strstreambuf::seekpos(streampos sp,
		ios_base::openmode which)
	{	// seek to memorized position
	streamoff off = (streamoff)sp;
	if (pptr() != 0 && _Seekhigh < pptr())
		_Seekhigh = pptr();	// update high water mark

	if (off == _BADOFF)
		;	// invalid seek
	else if (which & ios_base::in && gptr() != 0)
		{	// set input (and maybe output) pointer
		if (0 <= off && off <= _Seekhigh - eback())
			{	// set valid offset
			gbump(eback() - gptr() + off);
			if (which & ios_base::out && pptr() != 0)
				setp(pbase(), gptr(), epptr());
			}
		else
			off = _BADOFF;	// offset invalid, don't seek
		}
	else if (which & ios_base::out && pptr() != 0)
		{	// set output pointer
		if (0 <= off && off <= _Seekhigh - eback())
			pbump(eback() - pptr() + off);
		else
			off = _BADOFF;	// offset invalid, don't seek
		}
	else	// nothing to set
		off = _BADOFF;
	return (streampos(off));
	}

void strstreambuf::_Init(streamsize count, char *gp, char *pp,
	_Strstate mode)
	{	// initialize with possibly static buffer
	streambuf::_Init();
	_Minsize = _MINSIZE;
	_Pendsave = 0;
	_Seekhigh = 0;
	_Palloc = 0;
	_Pfree = 0;
	_Strmode = mode;

	if (gp == 0)
		{	// make dynamic
		_Strmode |= _Dynamic;
		if (_Minsize < count)
			_Minsize = count;
		}
	else
		{	// make static
		int size = count < 0 ? INT_MAX : count == 0 ? (int)strlen(gp) : count;
		_Seekhigh = gp + size;

		if (pp == 0)
			setg(gp, gp, gp + size);	// set read pointers only
		else
			{	// make writable too
			if (pp < gp)
				pp = gp;
			else if (gp + size < pp)
				pp = gp + size;
			setp(pp, gp + size);
			setg(gp, gp, pp);
			}
		}
	}

void strstreambuf::_Tidy()
	{	// free any allocated storage
	if ((_Strmode & (_Allocated | _Frozen)) != _Allocated)
		;	// no buffer to free
	else if (_Pfree != 0)
		(*_Pfree)(eback());	// free with function call
	else
		_DELETE_CRT_VEC(eback());	// free by deleting array

	_Seekhigh = 0;
	_Strmode &= ~(_Allocated | _Frozen);
	}
_STD_END

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