blob: c357219f0d63e6f830b4be5f757eb363c60c59b7 [file] [log] [blame]
/***************************************************************************
*
* istream.cc - definitions of basic_istream members
*
* $Id$
*
***************************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
* Copyright 1994-2006 Rogue Wave Software.
*
**************************************************************************/
_RWSTD_NAMESPACE (__rw) {
_EXPORT
template <class _CharT, class _Traits, class _NativeType>
_STD::basic_istream<_CharT, _Traits>&
__rw_extract (_STD::basic_istream<_CharT, _Traits> &__strm,
_NativeType &__val)
{
_RWSTD_ASSERT (0 != __strm.rdbuf ());
typedef _STD::istreambuf_iterator<_CharT, _Traits> _Iter;
typedef _STD::num_get<_CharT, _Iter> _NumGet;
_STD::ios_base::iostate __err = _STD::ios_base::goodbit;
// eat leading whitespace, catching exceptions from sentry
const typename _STD::basic_istream<_CharT, _Traits>::sentry
__ipfx (__strm /* , noskipws = false */);
if (__ipfx) {
_TRY {
_STD_USE_FACET (_NumGet, __strm.getloc ())
.get (_Iter (__strm), _Iter (), __strm, __err, __val);
}
_CATCH (...) {
__strm.setstate (__strm.badbit | _RW::__rw_rethrow);
}
}
if (_STD::ios_base::goodbit != __err)
__strm.setstate (__err);
return __strm;
}
} // namespace __rw
_RWSTD_NAMESPACE (std) {
template<class _CharT, class _Traits>
basic_istream<_CharT, _Traits>&
basic_istream<_CharT, _Traits>::
_C_ipfx (bool __noskipws, ios_base::iostate __errbits)
{
// extension - zero out irrespective of state so that gcount()
// called after any failed extraction (even formatted) reports 0
// and always count _all_ extracted characters
if (ios_base::goodbit != this->rdstate ()) {
this->setstate (ios_base::failbit);
return *this;
}
ios_base::iostate __state = ios_base::goodbit;
_TRY {
if (this->tie ())
this->tie ()->flush ();
if ( ios_base::eofbit == __errbits // passed by std::ws
|| !__noskipws && this->flags () & ios_base::skipws) {
// skip over leading whitespace
basic_streambuf<char_type, traits_type>* const __rdbuf =
this->rdbuf ();
_RWSTD_ASSERT (0 != __rdbuf);
const ctype<char_type> &__ctp =
_USE_FACET (ctype<char_type>, this->getloc ());
for ( ; ; ) {
const char_type* const __gptr = __rdbuf->gptr ();
const char_type* const __egptr = __rdbuf->egptr ();
if (__gptr < __egptr) {
// scan the sequence for the first non-whitespace char
const streamsize __nskip =
__ctp.scan_not (__ctp.space, __gptr, __egptr)
- __gptr;
__rdbuf->gbump (__nskip);
if (__nskip < __egptr - __gptr)
break;
}
else {
const int_type __c (__rdbuf->sgetc ());
if (traits_type::eq_int_type (__c, traits_type::eof ())) {
__state = __errbits;
break;
}
if (!__ctp.is (__ctp.space,
traits_type::to_char_type (__c)))
break;
__rdbuf->sbumpc ();
}
}
}
}
_CATCH (...) {
this->setstate (ios_base::badbit | _RW::__rw_rethrow);
}
if (__state)
this->setstate (__state);
return *this;
}
template<class _CharT, class _Traits>
typename basic_istream<_CharT, _Traits>::int_type
basic_istream<_CharT, _Traits>::
_C_unsafe_get (streamsize *__cnt /* = 0 */,
int_type __delim /* = eof() */,
int __flags /* = 0 */)
{
_RWSTD_ASSERT (0 != this->rdbuf ());
ios_base::iostate __err = ios_base::goodbit;
// initialize in case sgetc() below throws
int_type __c (traits_type::eof ());
_TRY {
// get next char without extracting
__c = this->rdbuf ()->sgetc ();
// extract delimiter or eos only if asked to
// extract whitespace only if it doesn't terminate input
if (traits_type::eq_int_type (__c, traits_type::eof ()))
__err = ios_base::eofbit
| (__flags & _C_faileof ? this->failbit : this->goodbit);
else if ( ( _C_eatdelim & __flags
|| !traits_type::eq_int_type (__c, __delim))
&& ( _C_eatnull & __flags
|| !traits_type::eq (traits_type::to_char_type (__c),
char_type ()))
&& ( !(_C_wsterm & __flags)
|| !_USE_FACET (ctype<char_type>, this->getloc ())
.is (ctype_base::space,
traits_type::to_char_type (__c)))) {
if (traits_type::eq_int_type (this->rdbuf ()->sbumpc (),
traits_type::eof ()))
__err = ios_base::failbit;
else if (__cnt)
++*__cnt; // increment number of extracted chars
}
}
_CATCH (...) {
this->setstate (ios_base::badbit | _RW::__rw_rethrow);
}
if (__err)
this->setstate (__err);
return __c;
}
template<class _CharT, class _Traits>
basic_istream<_CharT, _Traits>&
basic_istream<_CharT, _Traits>::
_C_get (basic_streambuf<char_type, traits_type> &__sb, int_type __delim)
{
_RWSTD_ASSERT (0 != this->rdbuf ());
ios_base::iostate __err = ios_base::goodbit;
const sentry __ipfx (*this, true /* noskipws */);
if (__ipfx) {
_C_gcount = 0;
_TRY {
for ( ; ; ) {
int_type __c (this->rdbuf ()->sgetc ());
if (traits_type::eq_int_type (__c, traits_type::eof ())) {
__err = ios_base::eofbit;
break;
}
if (traits_type::eq_int_type (__c, __delim))
break;
_TRY {
__c = __sb.sputc (traits_type::to_char_type (__c));
}
_CATCH (...) {
// indicate to the outer catch block the the
// exception rethrown from the call to setstate()
// below should be propagated without setting
// badbit (whose purpose is to indicates the
// "badness" of *this, not some other object)
__err = ios_base::failbit | _RW::__rw_rethrow;
// set failbit and rethrow if failbit is set in
// exceptions() despite 27.6.1.3, p12, bullet 4
this->setstate (__err);
break;
}
if (traits_type::eq_int_type (__c, traits_type::eof ())) {
__err = ios_base::failbit;
break;
}
++_C_gcount;
this->rdbuf ()->sbumpc ();
}
}
_CATCH (...) {
// will rethrow if `err' is set since the caught exception
// is the one thrown during output and rethrown by setstate()
// in the nested catch block above
if (ios_base::goodbit == __err)
__err = ios_base::badbit;
this->setstate (__err | _RW::__rw_rethrow);
}
}
// 27.6.1.3, p13
if (!gcount ())
__err |= ios_base::failbit;
if (__err)
this->setstate (__err);
return *this;
}
template<class _CharT, class _Traits>
basic_istream<_CharT, _Traits>&
basic_istream<_CharT, _Traits>::
read (char_type *__s, streamsize __n, int_type __delim, int __flags)
{
// if __s is 0 function doesn't store characters (used by ignore)
_RWSTD_ASSERT (0 <= __n);
_RWSTD_ASSERT (0 != this->rdbuf ());
const char_type __eos = char_type ();
const bool __getline = (_C_failend | _C_nullterm)
== ((_C_failend | _C_nullterm) & __flags);
// "clear" buffer if reading a null-terminated string
// follows the proposed resolution of lwg issue 243
if (__getline)
traits_type::assign (*__s, __eos);
// read and getline are unformatted (noskipws), others are formatted
const sentry __ipfx (*this, !(_C_skipws & __flags));
// 27.6.1.2.1, p1 and 27.6.1.3, p1: proceed iff sentry is okay
if (__ipfx) {
_C_gcount = 0;
// read at most n - 1 characters when null-terminating
while (__n) {
// handle 27.6.1.3, p17 and p18
if (0 == --__n && _C_nullterm & __flags) {
if (!__getline)
break;
const int_type __c (this->rdbuf ()->sgetc ());
if ( !traits_type::eq_int_type (__c, traits_type::eof ())
&& !traits_type::eq_int_type (__c, __delim))
break;
__flags &= ~_C_failend; // prevent failbit from being set
// will break out in the check below...
}
// get (possibly extract) next char
const int_type __c (_C_unsafe_get (&_C_gcount, __delim, __flags));
// eof or delimiter may terminate input
if ( traits_type::eq_int_type (__c, traits_type::eof())
|| traits_type::eq_int_type (__c, __delim))
break;
const char_type __ch = traits_type::to_char_type (__c);
// space or eos char may terminate input
if ( !(_C_eatnull & __flags) && traits_type::eq (__ch, __eos)
|| _C_wsterm & __flags
&& _USE_FACET (ctype<char_type>, this->getloc ())
.is (ctype_base::space, __ch))
break;
// ignore input if __s is null
if (__s)
traits_type::assign (*__s++, __ch);
}
if (_C_nullterm & __flags && __s)
traits_type::assign (*__s, __eos);
}
// fail if no chars extracted or if end of buffer has been reached
if ( _C_failnoi & __flags && !gcount ()
|| _C_failend & __flags && !__n)
this->setstate (ios_base::failbit);
return *this;
}
// 27.6.1.3, p28
template<class _CharT, class _Traits>
basic_istream<_CharT, _Traits>&
basic_istream<_CharT, _Traits>::
read (char_type *__s, streamsize __n)
{
_RWSTD_ASSERT (0 <= __n);
_RWSTD_ASSERT (0 != this->rdbuf ());
// 27.6.1.3, p28: sets ios_base::failbit if !this->good()
const sentry __ipfx (*this, true /* noskipws */);
// 27.6.1.2.1, p1 and 27.6.1.3, p1: proceed iff sentry is okay
if (__ipfx) {
_C_gcount = 0;
streamsize __nread = 0;
_TRY {
__nread = this->rdbuf ()->sgetn (__s, __n);
if (__nread >= 0)
_C_gcount = __nread;
}
_CATCH (...) {
this->setstate (ios_base::badbit | _RW::__rw_rethrow);
}
if (__n != __nread)
this->setstate (ios_base::eofbit | ios_base::failbit);
}
return *this;
}
template<class _CharT, class _Traits>
streamsize
basic_istream<_CharT, _Traits>::
readsome (char_type *__s, streamsize __n)
{
_RWSTD_ASSERT (0 != __s);
_RWSTD_ASSERT (0 <= __n);
_RWSTD_ASSERT (0 != this->rdbuf());
const sentry __ipfx (*this, true /* noskipws */);
if (__ipfx) {
_C_gcount = 0;
streamsize __nread = 0;
_TRY {
const streamsize __in_avail = this->rdbuf ()->in_avail ();
if (!__in_avail)
return 0;
if (__n > __in_avail)
__n = __in_avail;
// the call to sgetn() below is required to return >= 0
__nread = __n >= 0 ? this->rdbuf ()->sgetn (__s, __n) : -1;
if (__nread >= 0)
_C_gcount = __nread;
}
_CATCH (...) {
this->setstate (ios_base::badbit | _RW::__rw_rethrow);
}
if (__nread < 0) {
this->setstate (ios_base::eofbit);
__nread = 0;
}
return __nread;
}
else
this->setstate (ios_base::failbit);
return 0;
}
template<class _CharT, class _Traits>
typename basic_istream<_CharT, _Traits>::pos_type
basic_istream<_CharT, _Traits>::
tellg ()
{
_RWSTD_ASSERT (0 != this->rdbuf ());
const sentry __ipfx (*this, true /* noskipws */);
if (__ipfx && !this->fail ()) {
_TRY {
return this->rdbuf ()->pubseekoff (0, ios_base::cur, ios_base::in);
}
_CATCH (...) {
this->setstate (ios_base::badbit | _RW::__rw_rethrow);
}
}
return off_type (-1);
}
template<class _CharT, class _Traits>
basic_istream<_CharT, _Traits>&
basic_istream<_CharT, _Traits>::
putback (char_type __c)
{
const sentry __ipfx (*this, true /* noskipws */);
if (__ipfx) {
if (this->rdbuf ()) {
_TRY {
if (!traits_type::eq_int_type (this->rdbuf ()->sputbackc (__c),
traits_type::eof ()))
return *this;
}
_CATCH (...) {
this->setstate (ios_base::badbit | _RW::__rw_rethrow);
}
}
this->setstate (ios_base::badbit);
}
return *this;
}
template<class _CharT, class _Traits>
basic_istream<_CharT, _Traits>&
basic_istream<_CharT, _Traits>::
unget ()
{
const sentry __ipfx (*this, true /* noskipws */);
if (__ipfx) {
if (this->rdbuf ()) {
_TRY {
if (!traits_type::eq_int_type (this->rdbuf ()->sungetc (),
traits_type::eof ()))
return *this;
}
_CATCH (...) {
this->setstate (ios_base::badbit | _RW::__rw_rethrow);
}
}
this->setstate (ios_base::badbit);
}
return *this;
}
template<class _CharT, class _Traits>
int
basic_istream<_CharT, _Traits>::
sync ()
{
const sentry __ipfx (*this, true /* noskipws */);
if (__ipfx && this->rdbuf ()) {
_TRY {
if (-1 != this->rdbuf ()->pubsync ())
return 0;
}
_CATCH (...) {
this->setstate (ios_base::badbit | _RW::__rw_rethrow);
}
this->setstate (ios_base::badbit);
}
return -1;
}
template<class _CharT, class _Traits>
basic_istream<_CharT, _Traits>&
basic_istream<_CharT, _Traits>::
get (char_type *__s, streamsize __n, char_type __delim)
{
_RWSTD_ASSERT (0 != this->rdbuf ());
if (0 < __n) {
// lwg issue 243: store the NUL character before
// constructing the sentry object in case it throws
traits_type::assign (__s [0], char_type ());
}
const sentry __ipfx (*this, true /* noskipws */);
ios_base::iostate __err = ios_base::goodbit;
if (__ipfx) {
_C_gcount = 0;
_TRY {
basic_streambuf<char_type, traits_type>* const __rdbuf =
this->rdbuf ();
for ( ; __n > 1; ) {
streamsize __navail =
streamsize (__rdbuf->egptr () - __rdbuf->gptr ());
if (__n - 1 < __navail)
__navail = __n - 1;
if (__navail) {
char_type* const __gptr = __rdbuf->gptr ();
const char_type* const __pdelim =
traits_type::find (__gptr, __navail, __delim);
if (__pdelim) {
__navail = streamsize (__pdelim - __gptr);
if (!__navail)
break;
}
traits_type::copy (__s + _C_gcount, __gptr, __navail);
__rdbuf->gbump (__navail);
_C_gcount += __navail;
__n -= __navail;
}
else {
const int_type __c (__rdbuf->sgetc ());
if (traits_type::eq_int_type (__c, traits_type::eof ())) {
__err = ios_base::eofbit;
break;
}
const char_type __ch = traits_type::to_char_type (__c);
if (traits_type::eq (__ch, __delim))
break;
traits_type::assign (__s [_C_gcount++], __ch);
--__n;
__rdbuf->sbumpc ();
}
}
traits_type::assign (__s [_C_gcount], char_type ());
if (!_C_gcount)
__err |= ios_base::failbit;
}
_CATCH (...) {
this->setstate (ios_base::badbit | _RW::__rw_rethrow);
}
}
if (ios_base::goodbit != __err)
this->setstate (__err);
return *this;
}
template<class _CharT, class _Traits>
basic_istream<_CharT, _Traits>&
basic_istream<_CharT, _Traits>::
getline (char_type *__line, streamsize __size, char_type __delim)
{
_RWSTD_ASSERT (__size >= 0);
_RWSTD_ASSERT (!__size || __line);
_RWSTD_ASSERT (0 != this->rdbuf ());
char_type __dummy;
if (0 < __size) {
// lwg issue 243: store the NUL character before
// constructing the sentry object in case it throws
traits_type::assign (__line [0], char_type ());
}
else {
// use a dummy buffer to avoid having to check size
// again below, and prevent undefined behavior when
// size is negative
__line = &__dummy;
__size = 0;
}
const sentry __ipfx (*this, true /* noskipws */);
ios_base::iostate __err = ios_base::goodbit;
if (__ipfx) {
_C_gcount = 0;
basic_streambuf<char_type, traits_type>* const __rdbuf =
this->rdbuf ();
_TRY {
for ( ; ; ) {
const char_type* const __gptr = __rdbuf->gptr ();
const char_type* const __egptr = __rdbuf->egptr ();
// compute the lesser of the number of characters in the
// stream buffer and the size of the destination buffer
streamsize __navail = __egptr - __gptr;
if (__size < __navail)
__navail = __size;
if (__navail) {
// find the delimiter in the sequence if it exists
const char_type* const __pdel =
traits_type::find (__gptr, __navail, __delim);
if (__pdel) {
__navail = __pdel - __gptr + 1;
__size -= __navail - 1;
}
else if (__size == __navail)
__size -= --__navail;
else
__size -= __navail;
// copy including delimiter, if any
// (delimiter will be overwritten below)
traits_type::copy (__line + _C_gcount, __gptr, __navail);
_C_gcount += __navail;
// advance gptr()
__rdbuf->gbump (__navail);
if (__pdel) {
traits_type::assign (__line [_C_gcount - 1],
char_type ());
break;
}
if (2 > __size && __egptr - __gptr != __navail) {
traits_type::assign (__line [_C_gcount], char_type ());
__err = ios_base::failbit;
break;
}
}
else {
// no data in buffer, trigger underflow()
// note that streambuf may be unbuffered
const int_type __c (__rdbuf->sgetc ());
if (traits_type::eq_int_type (__c, traits_type::eof ())) {
traits_type::assign (__line [_C_gcount], char_type ());
__err = ios_base::eofbit;
break;
}
const char_type __ch = traits_type::to_char_type (__c);
if (traits_type::eq (__ch, __delim)) {
traits_type::assign (__line [_C_gcount], char_type ());
__rdbuf->sbumpc ();
_C_gcount++;
break;
}
if (2 > __size) {
traits_type::assign (__line [_C_gcount], char_type ());
__err = ios_base::failbit;
break;
}
traits_type::assign (__line [_C_gcount], __ch);
--__size;
__rdbuf->sbumpc ();
// increment gcount only _after_ sbumpc() but _before_
// the subsequent call to sgetc() to correctly reflect
// the number of extracted characters in the presence
// of exceptions thrown from streambuf virtuals
++_C_gcount;
}
}
}
_CATCH (...) {
this->setstate (ios_base::badbit | _RW::__rw_rethrow);
}
}
if (0 == _C_gcount)
__err |= ios_base::failbit;
if (__err)
this->setstate (__err);
return *this;
}
#ifdef _RWSTD_NO_UNDEFINED_TEMPLATES
template <class _CharT, class _Traits>
basic_istream<_CharT, _Traits>::sentry::
sentry (const sentry&)
: _RW::__rw_guard (0)
{
_RWSTD_ASSERT (!"not callable");
}
template <class _CharT, class _Traits>
void
basic_istream<_CharT, _Traits>::sentry::
operator= (const sentry&)
{
_RWSTD_ASSERT (!"not callable");
}
#endif // _RWSTD_NO_UNDEFINED_TEMPLATES
} // namespace std