/*************************************************************************** * * istream.cc - definitions of basic_istream members * * $Id: istream.cc 637130 2008-03-14 15:16:33Z faridz $ * *************************************************************************** * * 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 _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 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* const __rdbuf = this->rdbuf (); _RWSTD_ASSERT (0 != __rdbuf); const ctype &__ctp = _USE_FACET (ctype, 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 _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, 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 basic_istream<_CharT, _Traits>& basic_istream<_CharT, _Traits>:: _C_get (basic_streambuf &__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 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, 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 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 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 _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 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 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 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 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* 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 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* 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 basic_istream<_CharT, _Traits>::sentry:: sentry (const sentry&) : _RW::__rw_guard (0) { _RWSTD_ASSERT (!"not callable"); } template void basic_istream<_CharT, _Traits>::sentry:: operator= (const sentry&) { _RWSTD_ASSERT (!"not callable"); } #endif // _RWSTD_NO_UNDEFINED_TEMPLATES } // namespace std