//  streambuf : headerfile for the free standard C++ library
//  
//  Copyright (C) 1999 by the free standard C++ Library Team
//                        see AUTHORS for more details
//
//  Homepage : http://www.inf.fu-berlin.de/~mkrueger/fscl/
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Library General Public
//  License as published by the Free Software Foundation; either	
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Library General Public License for more details.
//  You should have received a copy of the GNU Library General Public
//  License along with this library; if not, write to the Free
//  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
//  version : 0.1 last modified : 17.09.99

#ifndef __CPP_STREAMBUF
#define __CPP_STREAMBUF

#include<cstddef>
#include<new>

#include<functional>
#include<iosfwd>
#include<ios>
#include<cstdlib>

// 27.5 Stream buffers

namespace std {	
	
	// 27.5.2 Template class basic_streambuf<charT, traits>

	template <class charT, class traits>
	class basic_streambuf
	{
		private:
			ios_base::openmode  openmode;
			locale              mylocale;
			bool locale_set;
			
			charT *gbeg, *gnext, *gend; // read buffer
			charT *pbeg, *pnext, *pend; // write buffer
			
		public:
			typedef charT                     char_type;
			typedef typename traits::int_type int_type;
			typedef typename traits::pos_type pos_type;
			typedef typename traits::off_type off_type;
			typedef traits                    traits_type;
						
			virtual ~basic_streambuf()
			{
			}
			
			// 27.5.2.2.1 locales:
			locale pubimbue(const locale &loc)
			{  
				locale tmp = getloc();
				imbue(loc);
				locale_set = true;
				return tmp;
			}
			
			locale getloc() const
			{  	
				if (locale_set) 
					return mylocale;
				else 
					return locale();
			}
			
			// 27.5.2.2.2 buffer and positioning:
			basic_streambuf<charT, traits> *pubsetbuf(charT* s, streamsize n)
			{ 
				return setbuf(s, n);
			}			
			pos_type pubseekoff(off_type off, ios_base::seekdir way, ios_base::openmode which = ios_base::in | ios_base::out)
			{ 
				return seekoff(off, way, which);
			}			
			pos_type pubseekpos(pos_type sp, ios_base::openmode which = ios_base::in | ios_base::out)
			{ 
				return seekpos(sp, which);
			}			
			int pubsync()
			{  
				return sync();
			}
			
			// Get and put areas:
			// 27.5.2.2.4 Get area:
			streamsize in_avail()
			{
				return egptr() - gptr() > 0 ? egptr() - gptr() : showmayc();
			}			
			int_type snextc()
			{
				if (sbumpc() == traits::eof())
					return traits::eof();
				return sgetc();
			}
			int_type sbumpc()
			{
				if (gptr() == 0) 
					return uflow();
				return traits::to_int_type(*gnext++);
			}
			
			int_type sgetc()
			{
				if (gptr() == 0)
					return underflow();
				return traits::to_int_type(*gptr());
			}
			
			streamsize sgetn(charT* s, streamsize n)
			{
				return xsgetn(s, n);
			}
			
			// 27.5.2.2.4 Putback:
			int_type sputbackc(charT c)
			{	
				if (gptr() == 0 || traits::eq(c, gptr()[-1]))
					return pbackfail(traits::to_int_type(c));
				return traits::to_int_type(*--gnext);
			}
			
			int_type sungetc()
			{	
				if (gptr() == 0)
					return pbackfail();
				return traits::to_int_type(*--gnext);
			}
			
			// 27.5.2.2.5 Put area:
			int_type sputc(charT c)
			{
				if (pptr() == 0)
					return overflow(traits::to_int_type(c));					
				traits::assign(*pnext++, c);
				return traits::to_int_type(c);
			}
			
			streamsize sputn(const charT* s, streamsize n)
			{
				return xsputn(s, n);
			}

		protected:

			basic_streambuf()
			{
				locale_set = false;
				gbeg = gnext = gend = 0;
				pbeg = pnext = pend = 0; 				
			}

			// 27.5.2.3.1 Get area:
		
			charT* eback() const
			{
				return gbeg;
			}
			
			charT* gptr()  const
			{			
				return gnext;
			}
			
			charT* egptr() const
			{			
				return gend;
			}
			
			void gbump(int n)
			{ 
				gnext += n;
			}

			void setg(charT* g1, charT* g2, charT* g3)
			{
				gbeg  = g1;
				gnext = g2;
				gend  = g3;
			}
			
			// 27.5.2.3.2 Put area:
			charT* pbase() const
			{
				return pbeg;
			}
			
			charT* pptr() const
			{
				return pnext;
			}
			
			charT* epptr() const
			{
				return pend;
			}
			
			void pbump(int n)
			{
				pnext += n;
			}
			
			void setp(charT* p1, charT* p2, charT* p3)
			{
				pbeg  = p1;
				pnext = p2;
				pend  = p3;
			}
			
			// 27.5.2.4 virtual functions:
			
			// 27.5.2.4.1 Locales:
			virtual void imbue(const locale &loc)
			{
				mylocale = loc;
			}
			
			// 27.5.2.4.2 Buffer management and positioning:
			virtual basic_streambuf<charT,traits> *setbuf(charT* s, streamsize n)
			{
				return this;
			}

			virtual pos_type seekoff(off_type off, ios_base::seekdir way, ios_base::openmode which = ios_base::in | ios_base::out)
			{
				return -1;
			}

			virtual pos_type seekpos(pos_type sp, ios_base::openmode which = ios_base::in | ios_base::out)
			{
				return -1;
			}

			virtual int sync()
			{
				return 0;
			}
			
			// 27.5.2.4.3 Get area:
			virtual int showmanyc()
			{
				return 0;
			}

			virtual streamsize xsgetn(charT* s, streamsize n)
			{
				streamsize w = n;
				while (w--) {
					int_type t = sbumpc();
					if (t == traits::eof())
						break;
					traits::assign(*s++, traits::to_char_type(t));
				}
				return n - w;
			}

			virtual int_type underflow()
			{
				return traits::eof();
			}

			virtual int_type uflow()
			{
				if (underflow() == traits::eof())
					return traits::eof();
				return traits::to_int_type(*gnext++);
			}

			// 27.5.2.4.4 Putback:
			virtual int_type pbackfail(int_type c = traits::eof())
			{
				return traits::eof();
			}
			
			// 27.5.2.4.5 Put area:
			virtual streamsize xsputn(const charT* s, streamsize n)			
			{
				streamsize w = n;
				while (w--) {
					if (sputc(*s++) == traits::eof())
						break;
				}
				return n - w;
			}
			
			virtual int_type overflow (int_type c = traits::eof())
			{
				return traits::eof();
			}
	};

	typedef basic_streambuf<char>     streambuf;
	typedef basic_streambuf<wchar_t> wstreambuf;
}

#endif
