/** -*- C++ -*-
 **
 **  KAI C++ Compiler
 **
 **  Copyright (C) 1996-2001 Intel Corp. All rights reserved.
 **/
/**
 **  Lib++  : The Modena C++ Standard Library,
 **           Version 2.4, October 1997
 **
 **  Copyright (c) 1995-1997 Modena Software Inc.
 **/
#ifndef __KAI_STREAMBUF
#define __KAI_STREAMBUF

#include <mcompile.h>
#include <ios>

namespace std {

template<class charT, class traits> 
class basic_streambuf {
public:
    // Types
    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:
    inline locale pubimbue(const locale &);
    inline locale getloc() const;

     // 27.5.2.2.2 buffers and positioning:
    inline basic_streambuf * pubsetbuf(char_type *, streamsize);
    inline pos_type pubseekoff(off_type off, ios_base::seekdir way, 
			       ios_base::openmode which=ios_base::in | ios_base::out);
    inline pos_type pubseekpos(pos_type sp, ios_base::openmode which=ios_base::in | ios_base::out);
    inline int pubsync();

    // Get and Put areas:
    // 27.5.2.2.3 Get areas:
    inline streamsize in_avail();
    inline int_type snextc();
    inline int_type sbumpc();
    inline int_type sgetc();
    inline streamsize sgetn(char_type *, streamsize);
    // SSS fix 
    void freeze(bool = true);	// freeze or unfreeze writing

    // 27.5.2.2.4 Putback:
    inline int_type sputbackc(char_type);
    inline int_type sungetc();
 
    // 27.5.2.2.5 Put areas:
    inline int_type sputc(charT c);
    inline streamsize sputn(const charT* , streamsize);
 
protected:
    basic_streambuf();

    // 27.5.2.3.1 Get area:
    inline char_type* eback() const;
    inline char_type* gptr() const;
    inline char_type* egptr() const;
    inline void gbump(int);
    inline void setg(char_type * gbeg, char_type *gnext, char_type *gend);
 
    // 27.5.2.3.2 Put area:
    inline char_type* pbase() const;
    inline char_type* pptr() const;
    inline char_type* epptr() const;
    inline void pbump(int);
    inline void setp(char_type *pbeg, char_type *pend);

    // 27.5.2.4 Virtual functions:
    // 27.5.2.4.1 Locales:
    virtual void imbue(const locale &);

#if KAI_NONSTD_STREAMBUF
public: 			/* Cfront makes these public */
#endif /* KAI_NONSTD_STREAMBUF */
    // 27.5.2.4.2 Buffer management and positioning:
    virtual basic_streambuf* setbuf(char_type*, streamsize);
    virtual pos_type seekoff(off_type off, ios_base::seekdir way, 
			     ios_base::openmode which=ios_base::in | ios_base::out);
    virtual pos_type seekpos(pos_type sp, ios_base::openmode which = ios_base::in | ios_base::out);
    virtual int sync();

protected:    
    // 27.5.2.4.3 Get area:
    // ISO says: The class summary for basic_streambuf, in 27.5.2, says that showmanyc has 
    // return type int. However, 27.5.2.4.3 says that its return type is streamsize
    // KAI has decided to resolve in favor of streamsize.
    virtual streamsize showmanyc();	// s how many c
    virtual streamsize xsgetn(char_type* s, streamsize n);
    virtual int_type underflow();
    virtual int_type uflow();

    // 27.5.2.4.4 Putback:
    virtual int_type pbackfail(int_type c=traits::eof());

    // 27.5.2.4.5 Put area:
    virtual streamsize xsputn(const charT* s, streamsize n);
    virtual int_type overflow(int_type c=traits::eof());
 
    //  protected data member
    locale       loc;
    char_type*   gbeg;
    char_type*   gnext;
    char_type*   gend;
    char_type*   pbeg;
    char_type*   pnext;
    char_type*   pend;

    // mutex locks for the get and put area.
    __KAI_DECL_SHARED_OBJ_LOCK(recursive_mutex,_mutex)
#if MSIPL_MULTITHREAD
    template<class CT,class TT> friend class basic_ios;
#endif

private:
    // to be undefined
    basic_streambuf(const basic_streambuf<charT, traits>&  rhs); 
    basic_streambuf& operator=(const basic_streambuf&  rhs); 
    template<class CT,class TT> friend class basic_ostream;
    template<class CT,class TT> friend class basic_istream;

    template<class charT1, class traits1, class Allocator1>
    friend basic_istream<charT1, traits1>&
    getline(basic_istream<charT1, traits1>& is,
            basic_string<charT1, traits1, Allocator1>& str, charT1 delim);
};

template<class charT, class traits>
inline basic_streambuf<charT, traits>::basic_streambuf() 
{
    gbeg=gnext=gend=pbeg=pnext=pend=0;
    loc = locale();
}

// 27.5.2.2.1 Locales:
template<class charT, class traits>
inline locale 
basic_streambuf<charT, traits>::pubimbue(const locale& loc_arg)
{
    locale  loc_sav=loc;
    imbue(loc_arg);
    return  loc_sav;
}
 
template<class charT, class traits>
inline locale 
basic_streambuf<charT, traits>::getloc() const 
{
    return loc;
}
 
// 27.5.2.2.2 Buffer management and positioning:
template<class charT, class traits>
inline basic_streambuf<charT, traits>* basic_streambuf<charT, traits>::
                                      pubsetbuf(char_type* s, streamsize n)
{
    return setbuf(s, n);
}

template<class charT, class traits>
inline basic_streambuf<charT, traits>::pos_type
basic_streambuf<charT, traits>::pubseekoff(off_type  off, 
					   ios_base::seekdir way, ios_base::openmode which)
{
    return seekoff(off, way, which);
}

template<class charT, class traits>
inline basic_streambuf<charT, traits>::pos_type 
basic_streambuf<charT, traits>::pubseekpos(pos_type sp, ios_base::openmode which)
{
    return seekpos(sp, which);
}

template<class charT, class traits>
inline int 
basic_streambuf<charT, traits>::pubsync()
{
    return sync();
}

// 27.5.2.2.3 Get area:
template<class charT, class traits>
inline streamsize 
basic_streambuf<charT, traits>::in_avail()
{
    return (gnext && gnext<gend ? (gend-gnext) : showmanyc());
}

template<class charT, class traits>
inline basic_streambuf<charT, traits>::int_type
basic_streambuf<charT, traits>::snextc()
{
    charT * p = gnext;
    if( p && p+1 < gend ) {
        // Make common case run fast.
        gnext = p+1;
	return traits::to_int_type(p[1]);
    } else {
        // In other cases, follow Standard (27.5.2.2.3) literally.
        int_type ch = sbumpc();
        return traits::eq_int_type(ch, traits::eof()) ? traits::eof() : sgetc();
    }
}

template<class charT, class traits>
inline basic_streambuf<charT, traits>::int_type
basic_streambuf<charT, traits>::sbumpc()
{
    return (gnext && gnext < gend ? traits::to_int_type(*gnext++) : uflow());
}

template<class charT, class traits>
inline basic_streambuf<charT, traits>::int_type
basic_streambuf<charT, traits>::sgetc()
{
    return (gnext && gnext<gend ? traits::to_int_type(*gnext) : underflow());
}

template<class charT, class traits>
inline streamsize 
basic_streambuf<charT, traits>::sgetn(char_type* s, streamsize n)
{
    return xsgetn(s, n);
}

// 27.5.2.2.4 Putback:
template<class charT, class traits> 
inline basic_streambuf<charT, traits>::int_type
basic_streambuf<charT, traits>::sputbackc(char_type c)
{
    return ( (gnext && gbeg < gnext && (traits::eq(c, * (gnext-1)))) 
	     ? traits::to_int_type(*--gnext) 
	     : pbackfail(traits::to_int_type(c)));
}

template<class charT, class traits> 
inline basic_streambuf<charT, traits>::int_type
basic_streambuf<charT, traits>::sungetc()
{
    return (gnext && gbeg < gnext ? traits::to_int_type(*--gnext)
	    : pbackfail());
}

// 27.5.2.2.5 Put area:
template<class charT, class traits>
inline basic_streambuf<charT, traits>::int_type
basic_streambuf<charT, traits>::sputc(char_type c)
{
    return (pnext && pnext < pend ? traits::to_int_type(*pnext++=c)
	    :overflow(traits::to_int_type(c)));
}

template<class charT, class traits>
inline streamsize 
basic_streambuf<charT, traits>::sputn(const charT * s, streamsize n)
{
    return xsputn(s, n);
}

// 27.5.2.3.1 Get area access:
template<class charT, class traits>
inline charT* 
basic_streambuf<charT, traits>::eback() const 
{
    return gbeg;
}

template<class charT, class traits> 
inline charT* 
basic_streambuf<charT, traits>::gptr() const 
{
    return gnext;
}

template<class charT, class traits>
inline charT* 
basic_streambuf<charT, traits>::egptr() const 
{
    return gend;
}

template<class charT, class traits>
inline void 
basic_streambuf<charT, traits>::gbump(int n)
{
    gnext+=n;
}

template<class charT, class traits>
inline void 
basic_streambuf<charT, traits>::setg(char_type* gbeg_arg, char_type* gnext_arg, 
				     char_type* gend_arg)
{
    gbeg=gbeg_arg; 
    gnext=gnext_arg;
    gend=gend_arg;
}

// 27.5.2.3.2 Put area access:
template<class charT, class traits>
inline charT* 
basic_streambuf<charT, traits>::pbase() const 
{
    return pbeg;
}

template<class charT, class traits>
inline charT* 
basic_streambuf<charT, traits>::pptr() const 
{
    return pnext;
}

template<class charT, class traits>
inline charT* 
basic_streambuf<charT, traits>::epptr() const 
{
    return pend;
}

template<class charT, class traits>
inline void 
basic_streambuf<charT, traits>::pbump(int n)
{
    pnext+=n;
}
 
template<class charT, class traits> 
inline void 
basic_streambuf<charT, traits>::setp(char_type* pbeg_arg, char_type* pend_arg)
{
    pnext=pbeg=pbeg_arg;
    pend=pend_arg;
}

template<class charT, class traits>
basic_streambuf<charT, traits>::~basic_streambuf() { }

// 27.5.2.4.1 Locales:
template<class charT, class traits> 
inline void
basic_streambuf<charT, traits>::imbue(const locale& locarg)
{ 
    loc=locarg;   //Virtual Func. Derived classes should take care of this
}

// 27.5.2.4.2 Buffer management and positioning:
// default behaviour
template<class charT, class traits> 
inline basic_streambuf<charT, traits>*
basic_streambuf<charT, traits>::setbuf(char_type*, streamsize)
{
    return this;
}
// default behaviour assuming this to be an invalid pos_type
template<class charT, class traits>
inline basic_streambuf<charT, traits>::pos_type 
basic_streambuf<charT, traits>::seekoff(off_type, ios_base::seekdir, 
					ios_base::openmode)
{
    return pos_type(-1);
}

// default behaviour assuming this to be an invalid pos_type
template<class charT, class traits> 
inline basic_streambuf<charT, traits>::pos_type 
basic_streambuf<charT, traits>::seekpos(pos_type, ios_base::openmode)
{
    return pos_type(-1);
}

// default behaviour 
template<class charT, class traits>
inline int basic_streambuf<charT, traits>::sync()
{
    return 0;
}

// 27.5.2.4.3 Get area:

// default behaviour 
template<class charT, class traits>
inline streamsize
basic_streambuf<charT, traits>::showmanyc()
{
    return 0;
}

template<class charT, class traits> 
streamsize
basic_streambuf<charT, traits>::xsgetn(char_type* s, streamsize n)
{
    streamsize  nvalue=0;
    off_type    nsize;
    int_type    ch;

    while (n > 0) {
        nvalue += (nsize = n>gend-gnext ? gend-gnext : n);
        n      -=  nsize;
        traits::copy(s, gnext, nsize);
        s += nsize; gnext += nsize;
        if (n > 0) { 
	    if (traits::eq_int_type( (ch = uflow()), traits::eof())) 
		break;
	    else { 
		*s++ = traits::to_char_type(ch); 
		++nvalue; 
		--n;
	    }
	}
    } 
    return nvalue;
} 

// default behaviour
template<class charT, class traits>
inline basic_streambuf<charT, traits>::int_type
basic_streambuf<charT, traits>::underflow()
{
    return traits::eof();
}
// default behaviour
template<class charT, class traits>
inline basic_streambuf<charT, traits>::int_type
basic_streambuf<charT, traits>::uflow()
{
    // default behaviour
    if (underflow() == traits::eof()) 
        return traits::eof();
    else 
        return traits::to_int_type(*gnext++);
}

// 27.5.2.4.4 Putback:

// default behaviour
template<class charT, class traits> 
inline basic_streambuf<charT, traits>::int_type
basic_streambuf<charT, traits>::pbackfail(int_type)
{
    return traits::eof();
}

// 27.5.2.4.5 Put area
template<class charT, class traits> 
streamsize
basic_streambuf<charT, traits>::xsputn(const charT* s, streamsize n)
{
    streamsize  nvalue=0;
    off_type    nsize;
    while (n > 0) {
        nsize = (n > pend - pnext ? pend - pnext : n);
        nvalue += nsize; 
        n -= nsize;
        traits::copy(pnext, s, nsize);
        s += nsize; pnext += nsize;
        if (n > 0) {
	    if (traits::eq_int_type(overflow(traits::to_int_type(*s)), 
                                    traits::eof()))
                break;
	    else {
                ++s;
                ++nvalue;
                --n;
	    }
	}
    } 
    return nvalue;
}

// default behaviour

template<class charT, class traits>
inline basic_streambuf<charT, traits>::int_type
basic_streambuf<charT, traits>::overflow(int_type)
{
    return traits::eof();
}

typedef basic_streambuf<char> streambuf;
#ifdef MSIPL_WCHART
typedef basic_streambuf<wchar_t> wstreambuf;
#endif

} // namespace std

#endif /* __KAI_STREAMBUF */
