/** -*- 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_ISTREAM
#define __KAI_ISTREAM

#include <mcompile.h>

#include <limits>

#include <iosfwd>
#include <locale>
//#include <extmath>
#include <streambuf>
#include <cerrno>

namespace std {

template<class charT, class traits>
class basic_istream : virtual public basic_ios<charT, traits>
{
    typedef basic_streambuf<charT, traits> streambuf_type;

public:
    typedef num_get<charT, istreambuf_iterator<charT, traits> > facet_type;
    typedef ctype<charT> ctype_facet_type;

    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;

    // 27.6.1.1.1 Constructor/Destructor:
    explicit basic_istream(streambuf_type*  sb);
    virtual ~basic_istream();
 
    // 27.6.1.1.2 Prefix/Suffix:

    class sentry 
    {
	bool ok_;
	typedef  ctype<char_type> ctype_facet_type;

    public:
	explicit sentry(basic_istream& is, bool noskipws=false);
	operator bool () const { return ok_; }

    private:  // Not to be defined
	sentry (const sentry&);
	sentry& operator= (const sentry&);
    };

    friend class sentry;

    // 27.6.1.2 Formatted input:
    /* inline keywords removed by KAI */
    basic_istream& operator>>(basic_istream& (*pf)(basic_istream&));
    basic_istream& operator>>(basic_ios<charT, traits>& (*pf)(basic_ios<charT, traits>&));
    basic_istream& operator>>(ios_base& (*pf)(ios_base&));
 
    basic_istream& operator>>(bool& n);
    basic_istream& operator>>(short& n);
    basic_istream& operator>>(unsigned short& n);
    basic_istream& operator>>(int& n);
    basic_istream& operator>>(unsigned int& n);
    basic_istream& operator>>(long& n);
    basic_istream& operator>>(unsigned long& n);
    basic_istream& operator>>(long long& n);
    basic_istream& operator>>(unsigned long long& n);
    basic_istream& operator>>(float& f);
    basic_istream& operator>>(double& f);
    basic_istream& operator>>(long double& f);

    basic_istream& operator>>(void*& p);
    basic_istream& operator>>(streambuf_type* sb);
 
    // 27.6.1.3 Unformatted input:
    streamsize gcount() const {return chcount;}

    int_type get();
    basic_istream& get(char_type& c);
    basic_istream& get(char_type* s, streamsize n) {return get(s, n, widen('\n'));};
    basic_istream& get(char_type*, streamsize, char_type);
    basic_istream& get(streambuf_type&);
    basic_istream& get(streambuf_type&, char_type);

    inline basic_istream& getline(char_type* s, streamsize n) {return getline(s, n, widen('\n'));}

    basic_istream& getline(char_type*, streamsize, char_type);

    basic_istream& ignore(streamsize n=1, int_type delim=traits::eof());
    int_type peek();
    basic_istream& read(char_type*, streamsize);
    streamsize readsome(char_type*, streamsize);

    basic_istream& putback(char_type);
    basic_istream& unget();
    int sync();

    pos_type tellg();
    basic_istream& seekg(pos_type);
    basic_istream& seekg(off_type, ios_base::seekdir);
 
    // KAI change - rewrite three versions of operator>>(in,s) to all simply
    // call new friend function __kai_extract_c_string, which does the real work.
    template<class charT1, class traits1, class charT2>
    friend basic_istream<charT1, traits1>&
    __kai_extract_c_string (basic_istream<charT1, traits1>& in, charT2* s);

    template<class charT1, class traits1, class charT2>
    friend basic_istream<charT1, traits1>&
    __kai_extract_char(basic_istream<charT1, traits1>& in, charT2& c);

private:
    streamsize chcount;
};

template<class charT, class traits, class charT2>
basic_istream<charT, traits>&
__kai_extract_c_string(basic_istream<charT, traits>& in, charT2* s)
{
    typedef basic_istream<charT, traits> IT;
    charT* ssav = s;
    ios_base::iostate flg = ios_base::goodbit;

    __KAI_LOCK_STREAM(in);
    MSIPL_TRY {
	IT::sentry s_(in);
	if (s_) {
	    int count = in.width() > 0 ? in.width() : numeric_limits<int>::max();
	    IT::int_type ch;
	    const IT::ctype_facet_type& ct = in.ctype_facet();
	    for (;0 < --count;) {	// Save a spot for the nul.
		ch = in.rdbuf()->sbumpc();
		if (ct.is(ct.space, ch)) {
		    in.rdbuf()->sputbackc(ch);
		    break;
		}
		if (traits::eq_int_type(ch, traits::eof())) {
		    flg |= IT::eofbit;
		    break;
		}
		if (traits::eq_int_type(ch, charT()))
		    break;
		*ssav++ = traits::to_char_type(ch);
	    }
	}
    }
    MSIPL_CATCH { flg |= IT::badbit; }
    in.width(0);
    *ssav = charT();
    if (ssav == s)
	flg |= IT::failbit;
    in.setstate(flg);
    return in;
}

template<class charT, class traits, class charT2>
basic_istream<charT, traits>&
__kai_extract_char(basic_istream<charT, traits>& in, charT2& c)
{
    typedef basic_istream<charT, traits> IT;
    ios_base::iostate flg = ios_base::goodbit;
    IT::int_type ch;
    __KAI_LOCK_STREAM(in);

    MSIPL_TRY {
	IT::sentry s_(in);
	if (s_ && !traits::eq_int_type(ch = in.rdbuf()->sbumpc(), traits::eof()))
	    c=traits::to_char_type(ch);
	else 
	    flg |= ios_base::failbit;
    }
    MSIPL_CATCH { flg |= IT::badbit; }
    if (flg != IT::goodbit)
	in.setstate(flg);
    return in;
}

template<class charT, class traits> 
inline basic_istream<charT, traits>::basic_istream(streambuf_type* sb) 
     : chcount(0) 
    // adr: Modena was initializing ios_base incorrectly.
    // See comments in <ostream> about corresponding constructor for ostream.
{
    init(sb);
}

template<class charT, class traits>	// Do not inline - this is the decider function
basic_istream<charT, traits>::~basic_istream() {}

template<class charT,class traits> extern basic_ostream<charT,traits>&  
flush(basic_ostream<charT,traits>& os);

template<class charT,class traits> extern void
__kai_do_flush(basic_ostream<charT,traits>* os);

template<class charT, class traits> 
basic_istream<charT, traits>::sentry::sentry( basic_istream<charT, traits>& is, bool noskipws)
    : ok_(false)
{
    __KAI_LOCK_STREAM(is);
    is.chcount = 0; 
    iostate flg = goodbit;
    MSIPL_TRY {
	if (is.state == ios_base::goodbit) {
	    if (is.tiestr) 
		__kai_do_flush(is.tiestr);
	    if (!noskipws &&(is.fmtfl & skipws)) {
		traits::int_type ch;
		const ctype_facet_type& ct = is.ctype_facet();
		do {
		    ch = is.sb->sbumpc();
		} while (!traits::eq_int_type(ch, traits::eof()) && ct.is(ct.space, ch));
		if (!traits::eq_int_type(ch, traits::eof())) 
		    is.sb->sputbackc(ch);
	    }
	} else 
	    flg = failbit;
    }
    MSIPL_CATCH { flg |= ios_base::badbit; }
    is.setstate(flg);
    if(!is.state) {
	ok_ = true;
    }
}

template<class charT, class traits> 
basic_istream<charT, traits>&
basic_istream<charT, traits>::operator>>(bool& n)
{
    iostate flg = goodbit;
    __KAI_LOCK_STREAM(*this);

    MSIPL_TRY {
	sentry s(*this); 
	if (s)
	    num_get_facet().get(*this, 0, *this, flg, n);
    }
    MSIPL_CATCH { flg |= badbit; }
    if (flg != goodbit)
	setstate(flg);
    return *this;
}

template<class charT, class traits> 
basic_istream<charT, traits>&
basic_istream<charT, traits>::operator>>(short& n)
{
    iostate flg = goodbit;
    __KAI_LOCK_STREAM(*this);

    MSIPL_TRY {
	sentry s_(*this);
	if (s_) {
	    long tmp;
	    num_get_facet().get(*this, 0, *this, flg, tmp);
	    if ( (n = tmp) != tmp) 
		flg |= failbit;
	}
    }
    MSIPL_CATCH { flg |= badbit; }
    if (flg!=goodbit)
	setstate(flg);
    return *this;
}

template<class charT, class traits> 
basic_istream<charT, traits>&
basic_istream<charT, traits>::operator>>(int& n)
{
    iostate flg = goodbit;
    __KAI_LOCK_STREAM(*this);

    MSIPL_TRY {
	sentry s(*this);
	if (s) {
	    long tmp;
	    num_get_facet().get(*this, 0, *this, flg, tmp);
	    if ( (n = tmp) != tmp)
		flg |= failbit;
	}
    }
    MSIPL_CATCH { flg |= badbit; }
    if (flg !=goodbit)
	setstate(flg);
    return *this;
}

template<class charT, class traits> 
basic_istream<charT, traits>&
basic_istream<charT, traits>::operator>>(long& n)
{
    iostate flg = goodbit;
    __KAI_LOCK_STREAM(*this);

    MSIPL_TRY {
	sentry s(*this);
	if (s) 
	    num_get_facet().get(*this, 0, *this, flg, n);
    }
    MSIPL_CATCH { flg |= badbit; }
    if (flg!=goodbit)
	setstate(flg);
    return *this;
}

template<class charT, class traits> 
basic_istream<charT, traits>&
basic_istream<charT, traits>::operator>>(long long& n)
{
    iostate flg = goodbit;
    __KAI_LOCK_STREAM(*this);

    MSIPL_TRY {
	sentry s(*this);
	if (s) 
	    num_get_facet().get(*this, 0, *this, flg, n);
    }
    MSIPL_CATCH { flg |= badbit; }
    if (flg!=goodbit)
	setstate(flg);
    return *this;
}

template<class charT, class traits> 
basic_istream<charT, traits>&
basic_istream<charT, traits>::operator>>(unsigned short& n)
{
    iostate flg = goodbit;
    __KAI_LOCK_STREAM(*this);

    MSIPL_TRY {
	sentry s_(*this);
	if (s_) 
	    num_get_facet().get(*this, 0, *this, flg, n);
    }
    MSIPL_CATCH { flg |= badbit; }
    if (flg!=goodbit)
	setstate(flg);
    return *this;
}

template<class charT, class traits> 
basic_istream<charT, traits>&
basic_istream<charT, traits>::operator>>(unsigned int& n)
{
    iostate flg = goodbit;
    __KAI_LOCK_STREAM(*this);

    MSIPL_TRY {
	sentry s_(*this);
	if (s_) 
	    num_get_facet().get(*this, 0, *this, flg, n);
    }
    MSIPL_CATCH { flg |= badbit; }
    if (flg!=goodbit)
	setstate(flg);
    return *this;
}

template<class charT, class traits> 
basic_istream<charT, traits>&
basic_istream<charT, traits>::operator>>(unsigned long& n)
{
    iostate flg = goodbit;
    __KAI_LOCK_STREAM(*this);

    MSIPL_TRY {
	sentry s_(*this);
	if (s_) 
	    num_get_facet().get(*this, 0, *this, flg, n);
    }
    MSIPL_CATCH { flg |= badbit; }
    if (flg!=goodbit)
	setstate(flg);
    return *this;
}

template<class charT, class traits> 
basic_istream<charT, traits>&
basic_istream<charT, traits>::operator>>(unsigned long long& n)
{
    iostate flg = goodbit;
    __KAI_LOCK_STREAM(*this);

    MSIPL_TRY {
	sentry s(*this);
	if (s) 
	    num_get_facet().get(*this, 0, *this, flg, n);
    }
    MSIPL_CATCH { flg |= badbit; }
    if (flg!=goodbit)
	setstate(flg);
    return *this;
}

template<class charT, class traits> 
basic_istream<charT, traits>&
basic_istream<charT, traits>::operator>>(float& n)
{
    iostate flg = goodbit;
    __KAI_LOCK_STREAM(*this);

    MSIPL_TRY {
	sentry s_(*this);
	if (s_) 
	    num_get_facet().get(*this, 0, *this, flg, n);
    }
    MSIPL_CATCH { flg |= badbit; }
    if (flg!=goodbit)
	setstate(flg);
    return *this;
}

template<class charT, class traits> 
basic_istream<charT, traits>&
basic_istream<charT, traits>::operator>>(double& n)
{
    iostate flg = goodbit;
    __KAI_LOCK_STREAM(*this);

    MSIPL_TRY {
	sentry s_(*this);
	if (s_) 
	    num_get_facet().get(*this, 0, *this, flg, n);
    }
    MSIPL_CATCH { flg |= badbit; }
    if (flg!=goodbit)
	setstate(flg);
    return *this;
}

template<class charT, class traits> 
basic_istream<charT, traits>&
basic_istream<charT, traits>::operator>>(long double& n)
{
    iostate flg = goodbit;
    __KAI_LOCK_STREAM(*this);

    MSIPL_TRY {
	sentry s_(*this);
	if (s_) 
	    num_get_facet().get(*this, 0, *this, flg, n);
    }
    MSIPL_CATCH { flg |= badbit; }
    if (flg!=goodbit)
	setstate(flg);
    return *this;
}

template<class charT, class traits> 
basic_istream<charT, traits>&
basic_istream<charT, traits>::operator>>(void*& n)
{
    iostate flg = goodbit;
    __KAI_LOCK_STREAM(*this);

    MSIPL_TRY {
	sentry  s_(*this);
	if (s_)
	    num_get_facet().get(*this, 0, *this, flg, n);
    }
    MSIPL_CATCH { flg |= badbit; }
    if (flg!=goodbit)
	setstate(flg);
    return *this;
}

template<class charT, class traits> 
inline basic_istream<charT, traits>& 
basic_istream<charT, traits>::operator>>(basic_istream&(*pf)(basic_istream&))
{
    return (*pf)(*this);
}

template<class cT, class ts> 
inline basic_istream<cT, ts>&
basic_istream<cT, ts>::operator>>(basic_ios<cT, ts>&(*pf)(basic_ios<cT, ts>&))
{
    (*pf)(*this); 
    return *this;
}
    
template<class charT, class traits> 
inline basic_istream<charT, traits>&
basic_istream<charT, traits>::operator>>(ios_base&(*pf)(ios_base&))
{
    (*pf)(*this); 
    return *this;
}
    
template<class charT, class traits> 
basic_istream<charT, traits>&
basic_istream<charT, traits>::operator>>(streambuf_type* buf)
{
    iostate flg = goodbit;
    int_type ch;
    bool res = false;
    __KAI_LOCK_STREAM(*this);

    MSIPL_TRY {
	sentry s_(*this);
	if (buf && s_) {
	    while (!traits::eq_int_type(ch = sb->sbumpc(), traits::eof())) {
		if (traits::eq_int_type(buf->sputc(traits::to_char_type(ch)), traits::eof())) {
		    sb->sputbackc(ch);
		    break;
		}
		res = true;
	    }
	    if (traits::eq_int_type(ch, traits::eof()))
		flg |= eofbit;
	}
	if (!res) 
	    flg |= failbit;
    }
    MSIPL_CATCH { flg |= badbit; }
    if (flg!=goodbit)
	setstate(flg);
    return *this;
}

template<class charT, class traits> 
basic_istream<charT, traits>::int_type 
basic_istream<charT, traits>::get()
{
    __KAI_LOCK_STREAM(*this);
    // Tests ordered to reject quickly in common rejection cases.
    streambuf_type* sbuf = sb;
    if( sbuf && sbuf->gnext && sbuf->gnext<sbuf->gend && !state && !tiestr ) {
        // Fast case.
        chcount=1;
        return traits::to_int_type(*sbuf->gnext++);
    } else {
	iostate flg = goodbit;
	MSIPL_TRY {
	    int_type ch;
	    sentry s_(*this, true);
	    if (s_) {
		if (traits::eq_int_type(ch=sb->sbumpc(),traits::eof()))
		    flg|=failbit|eofbit;
		else {
		    chcount=1;
		    return ch;
		}
	    } else {
		flg |= failbit;
	    }
	}
	MSIPL_CATCH { flg |= badbit; }
	if (flg!=goodbit)
	    setstate(flg);
	return traits::eof();
    }
}

template<class charT, class traits> 
basic_istream<charT, traits>&
basic_istream<charT, traits>::get( char_type& c ) 
{
    __KAI_LOCK_STREAM(*this);
    // Tests ordered to reject quickly in common rejection cases.
    streambuf_type* sbuf = sb;
    if( sbuf && sbuf->gnext && sbuf->gnext<sbuf->gend && !state && !tiestr ) {
        // Fast case.
        chcount=1;
        c = *sbuf->gnext++;
    } else {
	iostate flg = goodbit;
	MSIPL_TRY {
	    int_type ch;
	    sentry s_(*this, true);
	    if (s_) {
		if (traits::eq_int_type(ch=sb->sbumpc(),traits::eof()))
		    flg|=failbit|eofbit;
		else {
		    chcount=1;
		    c = traits::to_char_type(ch);
		}
	    } else {
		flg |= failbit;
	    }
	}
	MSIPL_CATCH { flg |= badbit; }
	if (flg!=goodbit)
	    setstate(flg);
    }
    return *this;
}

template<class charT, class traits> 
basic_istream<charT, traits>&
basic_istream<charT, traits>::get(char_type* s, streamsize n, char_type delim)
{
    iostate flg = goodbit;
    __KAI_LOCK_STREAM(*this);

    MSIPL_TRY {
	sentry s_(*this, true);
	if (s_ && n) {
	    int_type ch;
	    while (--n) {
		if (traits::eq_int_type(ch = sb->sbumpc(), traits::eof())) {
		    flg |= eofbit;
		    break;
		} 
		if (traits::to_char_type(ch) == delim) {
		    sb->sputbackc(ch);
		    break;
		}
		*s++ = traits::to_char_type(ch); 
		chcount++;
	    }
	}
    }
    MSIPL_CATCH { flg |= badbit; }
    *s = charT();
    if (!chcount) 
	flg |= failbit;
    if (flg!=goodbit)
	setstate(flg);
    return *this;
}

template<class charT, class traits> 
basic_istream<charT, traits>&
basic_istream<charT, traits>::get(streambuf_type& buf, char_type delim)
{
    iostate flg = goodbit;
    __KAI_LOCK_STREAM(*this);

    MSIPL_TRY {
	int_type ch;
	sentry s_(*this, true);
	if (s_) {
	    while (1) {
		if (traits::eq_int_type(ch = sb->sbumpc(), traits::eof())) {
		    flg |= eofbit;
		    break;
		}
		if (traits::eq_int_type(ch, delim)
		    || traits::eq_int_type(buf.sputc(traits::to_char_type(ch)), traits::eof())) {
		    sb->sputbackc(ch);
		    break;
		}
		chcount++;
	    }
	}
    }
    MSIPL_CATCH { flg |= badbit; }
    if (!chcount) 
	flg |= failbit;
    if (flg!=goodbit)
	setstate(flg);
    return *this;
}

template<class charT, class traits> 
inline basic_istream<charT, traits>&
basic_istream<charT, traits>::get(streambuf_type& sb)
{
    return get(sb, widen('\n'));
} 

template<class charT, class traits> 
basic_istream<charT, traits>&
basic_istream<charT, traits>::getline(char_type* s, streamsize n, char_type delim)
{
    iostate flg = goodbit;
    __KAI_LOCK_STREAM(*this);

    MSIPL_TRY {
	sentry s_(*this, true);
	if (s_ && n>0) {
	    int_type ch;
	    while (1) {
		if (traits::eq_int_type(ch = sb->sbumpc(), traits::eof())) {
		    flg |= eofbit; 
		    break;
		}
		if (traits::to_char_type(ch) == delim) {
		    chcount++;
		    break;
		} 
		if (!--n) {
		    sb->sputbackc(ch);
		    flg |= failbit; 
		    break;
		}
		*s++ = traits::to_char_type(ch);
		chcount++;
	    }
	}
    }
    MSIPL_CATCH { flg |= badbit; }
    *s = charT();
    if (!chcount) 
	flg |= failbit;
    if (flg!=goodbit)
	setstate(flg);

    return *this;
}

template<class charT, class traits> 
basic_istream<charT, traits>&
basic_istream<charT, traits>::ignore(streamsize n, int_type delim)
{
    iostate flg = goodbit;
    __KAI_LOCK_STREAM(*this);

    MSIPL_TRY {
	sentry s_(*this, true);
	if (s_) {
	    int_type ch;
	    for ( ; n>0; --n )   // Changed from while by KAI to avoid HP/UX 11 compiler bug.
		if (traits::eq_int_type(ch = sb->sbumpc(), traits::eof())) {
		    flg |= eofbit; 
		    break;
		} else { 
		    ++chcount;
		    if (ch == delim)
			break;
		}
	}
    }
    MSIPL_CATCH { flg |= badbit; }
    if (flg!=goodbit)
	setstate(flg);
    return *this;
}

template<class charT, class traits> 
basic_istream<charT, traits>::int_type 
basic_istream<charT, traits>::peek()
{
    iostate flg = goodbit;
    int_type ch = traits::eof(); 
    __KAI_LOCK_STREAM(*this);

    MSIPL_TRY {
	sentry s_(*this, true);
	if (s_ && traits::eq_int_type(ch = sb->sgetc(), traits::eof()))
	    flg |= eofbit; 
    }
    MSIPL_CATCH { flg |= badbit; }
    if (flg!=goodbit)
	setstate(flg);
    return ch;
}

template<class charT, class traits> 
basic_istream<charT, traits>&
basic_istream<charT, traits>::read(char_type* s, streamsize n)
{
    __KAI_LOCK_STREAM(*this);
    // Tests ordered to reject quickly in common rejection cases.
    streambuf_type* sbuf = sb;
    if( sbuf && sbuf->gnext && n<=sbuf->gend-sbuf->gnext && !state && !tiestr && sbuf->gnext<sbuf->gend )
    {
        // Fast case.
        traits::copy( s, sbuf->gnext, n );
        sb->gnext+=n;
	chcount = n;
    } else {
	iostate flg = goodbit;
	MSIPL_TRY {
	    sentry s_(*this, true);
	    if (!s_ ||(chcount = sb->sgetn(s, n)) != n) 
		flg |= failbit | eofbit;
	}
	MSIPL_CATCH { flg |= badbit; }
	if (flg!=goodbit)
	    setstate(flg);
    }
    return *this;
}

template<class charT, class traits> 
streamsize 
basic_istream<charT, traits>::readsome(char_type* s, streamsize n)
{
    __KAI_LOCK_STREAM(*this);

    // Tests ordered to reject quickly in common rejection cases.
    streambuf_type* sbuf = sb;
    if( sbuf && sbuf->gnext && n<=sbuf->gend-sbuf->gnext && !state && !tiestr && sbuf->gnext<sbuf->gend )
    {
        // Fast case.
        traits::copy( s, sbuf->gnext, n );
        sb->gnext+=n;
	chcount = n;
    } else {
        iostate flg = goodbit;
	chcount = 0;
	MSIPL_TRY {
	    sentry s_(*this, true);
	    if (s_) {
		// adr: Modena's implementation using sgetn was just plain wrong.
		// It called sgetn without checking in_avail, and thus could
		// lead to calling uflow, which is not permitted by any recent draft!
		streamsize m = sb->in_avail();		
		if ( m==(streamsize)-1 ) {
		    flg |= eofbit;
		} else if ( m>0 ) {
		    if ( m>n ) m=n;
		    chcount = sb->sgetn(s, m);
		}
	    }
	    else
		flg |= failbit;
	}
	MSIPL_CATCH { flg |= badbit; }
	if (flg!=goodbit)
	    setstate(flg);
    }
    return chcount;
}

template<class charT, class traits> 
basic_istream<charT, traits>&
basic_istream<charT, traits>::putback(char_type c)
{
    iostate flg = goodbit;
    __KAI_LOCK_STREAM(*this);

    MSIPL_TRY {
	sentry s_(*this, true);
	if (!sb) 
	    flg |= badbit; 
	else
	    if (state) 
		flg |= failbit; 
	    else
		if (traits::eq_int_type(sb->sputbackc(c), traits::eof()))
		    flg |= badbit;
    }
    MSIPL_CATCH { flg |= badbit; }
    if (flg!=goodbit)
	setstate(flg);
    return *this;
}

template<class charT, class traits> 
basic_istream<charT, traits>&
basic_istream<charT, traits>::unget()
{
    iostate flg = goodbit;
    __KAI_LOCK_STREAM(*this);

    MSIPL_TRY {
	sentry s_(*this, true);
	if (!sb) 
	    flg |= badbit; 
	else
	    if (state) 
		flg |= failbit; 
	    else
		if (traits::eq_int_type(sb->sungetc(), traits::eof())) 
		    flg |= badbit;
    }
    MSIPL_CATCH { flg |= badbit; }
    if (flg!=goodbit)
	setstate(flg);
    return *this;
}

template<class charT, class traits> 
int basic_istream<charT, traits>::sync() {
    int ret = -1;
    iostate flg = goodbit;
    __KAI_LOCK_STREAM(*this);

    MSIPL_TRY {
	sentry s_(*this, true); 
	if (sb) 
	    if (sb->pubsync() == -1) 
		flg |= badbit, ret = traits::eof(); 
	    else
		ret = 0;
    }
    MSIPL_CATCH { flg |= badbit; }
    if (flg!=goodbit)
	setstate(flg);
    return ret;
}

template<class charT, class traits> 
inline basic_istream<charT, traits>::
pos_type basic_istream<charT, traits>::tellg()
{
    __KAI_LOCK_STREAM(*this);
    sentry(*this, true); 
    return (state&badbit || state&failbit) ? pos_type(-1): 
	sb->pubseekoff(0, ios_base::cur, ios_base::in);
}

template<class charT, class traits> 
inline basic_istream<charT, traits>&
basic_istream<charT, traits>::seekg(off_type off, ios_base::seekdir dir)
{
    __KAI_LOCK_STREAM(*this);
    sentry(*this, true); 
    // KAI added ios_base::in - see Issue 136 of WG21's Library Issues list
    if (!(state & badbit) && !(state & failbit)) 
	sb->pubseekoff(off, dir, ios_base::in);
    return *this;
}

template<class charT, class traits> 
inline basic_istream<charT, traits>&
basic_istream<charT, traits>::seekg(pos_type pos)
{
    __KAI_LOCK_STREAM(*this);
    sentry(*this, true); 
    // KAI added ios_base::in - see Issue 136 of WG21's Library Issues list
    if (!(state & badbit) && !(state & failbit)) 
	sb->pubseekpos(pos, ios_base::in);
    return *this;
}


// KAI change - rewrite three versions of operator>>(in,s) to all simply
// call new member function __kai_extract_c_string, which does the real work.
// The new member function is inline, since it has only three call sites.
template<class charT,class traits> 
inline basic_istream<charT,traits>&
operator>>(basic_istream<charT,traits>& in,charT* s)
{
    return __kai_extract_c_string(in, (charT*)(s));
}

template<class charT,class traits>
inline basic_istream<charT,traits>&
operator>>(basic_istream<charT,traits>& in,unsigned char* s)
{
    return __kai_extract_c_string(in, (charT*)(s));
}

template<class charT,class traits>
inline basic_istream<charT,traits>&
operator>>(basic_istream<charT,traits>& in,signed char* s)
{
    return __kai_extract_c_string(in, (charT*)(s));
}

// KAI change - rewrite three versions of operator>>(in,c) to all simply
// call new member function __kai_extract_char, which does the real work.
template<class charT,class traits>
inline basic_istream<charT,traits>&
operator>>(basic_istream<charT,traits>& in,charT& c)
{
    return __kai_extract_char(in, c);
}

template<class charT,class traits>
inline basic_istream<charT,traits>&
operator>>(basic_istream<charT,traits>& in,unsigned char& c)
{
    return __kai_extract_char(in, c);
}

template<class charT,class traits>
inline basic_istream<charT,traits>&
operator>>(basic_istream<charT,traits>& in,signed char& c)
{
    return __kai_extract_char(in, c);
}

typedef basic_istream<char, char_traits<char> > istream;

#ifdef KAI_WCHAR_T
typedef basic_istream<wchar_t, char_traits<wchar_t> > wistream;
#endif

// 27.6.1.2.3 Character extraction templates:
template<class charT, class traits> 
basic_istream<charT, traits>&
ws(basic_istream<charT, traits>& is)
{
    typedef basic_istream<charT, traits> IT;
    __KAI_LOCK_STREAM(is);

    ios_base::fmtflags fmtflag_sav = is.setf(ios_base::skipws);
    IT::sentry s_(is);
    is.flags(fmtflag_sav);

    if (traits::eq_int_type(is.rdbuf()->sgetc(), traits::eof()))
	is.setstate(ios_base::eofbit);
    return is;
}

} // namespace std

// 27.6.1.5 says that <istream> declares std::iostream
#include <iostreambase>

#endif /* __KAI_ISTREAM */
