/************************************************************************ * * 27.readsome.cpp - test exercising istream::readsome() * * $Id: 27.istream.readsome.cpp 503954 2007-02-06 01:59:05Z sebor $ * ************************************************************************ * * 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 2003-2007 Rogue Wave Software. * **************************************************************************/ #include #include #include #include // for UserChar, UserTraits #include // for rw_printf() /***********************************************************************/ template struct Streambuf: std::basic_streambuf { typedef std::basic_streambuf Base; typedef typename Base::traits_type traits_type; typedef typename Base::int_type int_type; // value returned from showmanyc() int showmanyc_; // underflow() will return eof () after extracting this many chars int fail_after_; // underflow() will throw am exception after extracting this many chars int throw_after_; const charT *end_; // the end of the buffer (future eback()) Streambuf (const charT *gbeg, const charT *gend) : Base (), showmanyc_ (0), fail_after_ (-1), // never fail throw_after_ (-1), // never throw end_ (gend) { this->setg (_RWSTD_CONST_CAST (charT*, gbeg), _RWSTD_CONST_CAST (charT*, gbeg), _RWSTD_CONST_CAST (charT*, gbeg)); } const charT* pubeback () const { return this->eback (); } const charT* pubgptr () const { return this->gptr (); } const charT* pubegptr () const { return this->egptr (); } /* virtual */ std::streamsize showmanyc () { #ifndef _RWSTD_NO_EXCEPTIONS if (-2 == showmanyc_) throw (const char*)"showmanyc"; #endif // _RWSTD_NO_EXCEPTIONS return showmanyc_; } /* virtual */ int_type underflow () { if (this->gptr () == end_) return traits_type::eof (); if (throw_after_ == this->gptr () - this->eback ()) { #ifndef _RWSTD_NO_EXCEPTIONS throw (const char*)"underflow"; #else // if defined (_RWSTD_NO_EXCEPTIONS) return traits_type::eof (); #endif // _RWSTD_NO_EXCEPTIONS } if (fail_after_ == this->gptr () - this->eback ()) return traits_type::eof (); this->setg (this->eback (), this->gptr (), this->gptr () + 1); return traits_type::to_int_type (*this->gptr ()); } }; /*********************************************************************** 27.6.1.3, p30 and 31 streamsize readsome (char_type* s, streamsize n); -30- Effects: If !good() calls setstate(failbit) which may throw an exception, and return. Otherwise extracts characters and stores them into successive locations of an array whose first element is designated by s. -- If rdbuf()­>in_avail() == ­1, calls setstate(eofbit) (which may throw ios_base::failure (27.4.4.3)), and extracts no characters; -- If rdbuf()­>in_avail() == 0, extracts no characters -- If rdbuf()­>in_avail() > 0, extracts min(rdbuf()­>in_avail(), n)). -31- Returns: The number of characters extracted. ************************************************************************/ void memfun_info (int line, const char *cname, const char *tname) { // format the ISTREAM environment variable w/o writing // out any output rw_fprintf (0, "%{$ISTREAM!:@}", "%{?}istream%{:}%{?}wistream" "%{:}basic_istream<%s, %s>%{;}%{;}", 'c' == *cname && 'c' == *tname, 'w' == *cname && 'c' == *tname, cname, tname); rw_info (0, 0, line, "std::%{$ISTREAM}::readsome (char_type*, streamsize)"); } /************************************************************************/ extern const std::ios_base::iostate states[] = { std::ios_base::badbit, std::ios_base::eofbit, std::ios_base::failbit, std::ios_base::goodbit, std::ios_base::badbit | std::ios_base::eofbit, std::ios_base::badbit | std::ios_base::failbit, std::ios_base::eofbit | std::ios_base::failbit, std::ios_base::badbit | std::ios_base::eofbit | std::ios_base::failbit }; extern const unsigned nstates = sizeof states / sizeof *states; template void test_readsome (const charT *cbuf, const Traits*, unsigned cbuf_size, unsigned i, // index into states unsigned j, // number of chars to read unsigned k, // when underflow() will fail int l, // value returned from showmanyc() unsigned m) // how underflow should fail() { typedef std::basic_istream Istream; static unsigned iter = 0; // iteration counter // construct a stream buffer object and initialize its read // sequence with the character buffer Streambuf sb (cbuf, cbuf + cbuf_size - 1); sb.showmanyc_ = l; const char* err_type = 0; if (m < 1) { // have the stream buffer object's underflow() fail (by // throwing an exception if possible) after k characters // have been extracted (this object calls underflow() for // every char) sb.throw_after_ = k; err_type = "threw"; } else { // have the stream buffer object's underflow() fail by // returning eof after k characters have been extracted // (this object calls underflow() for every char) sb.fail_after_ = k; err_type = "returned EOF"; } // construct an istream object and initialize it with the user // defined streambuf object Istream is (&sb); // set the stream object's initial state is.setstate (states [i]); // the number of extracted whitespace characters expected to // be reported by gcount() must equal the number of successful // extractions computed by the the stream buffer overridden // underflow member function const int extract = is.good () ? j < k ? int (j) < l ? j : l < 0 ? 0 : l : int (k) < l ? k : l < 0 ? 0 : l : 0; charT buf [256] = { 0 }; std::streamsize nread = -1; // format the FCALL environment variable so that it can be // conveniently used in diagnostics below rw_fprintf (0, "%u. %{$FCALL!:@}", iter, "%{$ISTREAM}(%{*Ac}).readsome(%p, %d)", int (sizeof *cbuf), cbuf, buf, j); #ifndef _RWSTD_NO_EXCEPTIONS const char *caught = 0; // on every other iteration set badbit in exceptions to check // that the thrown object is propagated by the function if (k % 2 && !is.bad ()) is.exceptions (std::ios_base::badbit); try { nread = is.readsome (buf, j); } catch (const char *s) { caught = s; } catch (...) { caught = "..."; rw_assert (0, 0, __LINE__, "%{$FCALL} threw an exception of unexpected type"); } ////////////////////////////////////////////////////////////////// // verify that the function propagates exceptions thrown from the // streambuf object only when badbit is set in the stream object's // exceptions() rw_assert (!caught || (k % 2), 0, __LINE__, "%{$FCALL} unexpectedly propagated an exception"); #else // if defined (_RWSTD_NO_EXCEPTIONS) nread = is.readsome (buf, j); #endif // _RWSTD_NO_EXCEPTIONS ////////////////////////////////////////////////////////////////// // verify that the function returned the expected number of // extracted characters const std::streamsize extracted = sb.pubgptr () - sb.pubeback (); rw_assert (extract == extracted, 0, __LINE__, "%{$FCALL} expected to extract %d chars, got %u; " "initial state = %{Is}, underflow %s at extraction %u", extract, extracted, states [i], err_type, k); ////////////////////////////////////////////////////////////////// // verify that the expected number of characters have been // extracted from the stream rw_assert (cbuf + extract == sb.pubgptr (), 0, __LINE__, "%{$FCALL} expected to extract %d chars, got %u; " "initial state = %{Is}, underflow %s at extraction %u", extract, extracted, states [i], err_type, k); ////////////////////////////////////////////////////////////////// // verify that the extracted characters match those in the buffer rw_assert (0 == std::char_traits::compare (buf, cbuf, extract), 0, __LINE__, "%{$FCALL} expected to extract the first %d chars, got %{*Ac}", extract, int (sizeof *buf), buf); ////////////////////////////////////////////////////////////////// // verify that gcount() correctly reflects the number of // characters successfully extracted from the stream rw_assert (extract == is.gcount (), 0, __LINE__, "%{$FCALL}: gcount() == %d, got %d; initial state = %{Is}, " "underflow %s at extraction %u", extract, is.gcount (), states [i], err_type, k); ////////////////////////////////////////////////////////////////// // verify the state of the stream object after the function call // expected stream state after the function call is unchanged // (i.e., the initial stream state), except... std::ios_base::iostate expect_state = states [i]; if (!states [i]) { #ifndef _RWSTD_NO_EXCEPTIONS // ...if an extraction is attempted, or even if the first // character on the stream is peeked at, and an exception // is thrown during input, badbit should be set, otherwise // if in_avail() returned -1, eofbit should be set, else // the state should be good if (-2 == l) expect_state = std::ios_base::badbit; else if (l < 0) expect_state = std::ios_base::eofbit; else expect_state = std::ios_base::goodbit; #else // if defined (_RWSTD_NO_EXCEPTIONS) if (l < 0) expect_state = std::ios_base::eofbit; else expect_state = std::ios_base::goodbit; #endif // _RWSTD_NO_EXCEPTIONS } else { // ...if the initial stream state is not good, failbit // must be set expect_state = states [i] | std::ios_base::failbit; } rw_assert (is.rdstate () == expect_state, 0, __LINE__, "%{$FCALL}: rdstate() == %{Is}, got %{Is}; " "extracted %u characters; " "initial state = %{Is}, underflow %s at extraction %u", expect_state, is.rdstate (), extracted, states [i], err_type, k); ++iter; } /***********************************************************************/ template void test_readsome (const charT*, const Traits*, const char *cname, const char *tname) { memfun_info (__LINE__, cname, tname); ////////////////////////////////////////////////////////////// // exercise 27.6.1.3, p1 const charT cbuf[] = { ' ', 'a', ' ', 'b', 'c', '\0' }; const unsigned cbuf_size = sizeof cbuf / sizeof *cbuf; unsigned iter = 0; // iteration counter // iterate over all possible settings of the stream state for (unsigned i = 0; i != nstates; ++i) { // call readsome(..., j) to extract j characters for (unsigned j = 0; j != cbuf_size - 1; ++j) { // have underflow() fail after the `k-th' extraction for (unsigned k = 0; k != j + 1; ++k) { // return `l' from showmanyc(); -2 will throw for (int l = -4; l != int (k); ++l) { // if (0 == m), underflow() will throw an exception // at `k-th' extraction, otherwise the function will // return EOF for (unsigned m = 0; m != 2; ++m, ++iter) { // prevent causing underflow() to fail by // returning EOF when in_avail() promised // it wouldn't (by returning a value // greater than the number of extractions // underflow() will allow to succeed) if (1U == m && int (k) < l) continue; test_readsome (cbuf, (Traits*)0, cbuf_size, i, j, k, l, m); } } } } } } /***********************************************************************/ static int opt_char; static int opt_wchar; static int opt_char_traits; static int opt_user_traits; static int run_test (int, char**) { // introduce char_traits into scope using namespace std; #undef TEST #define TEST(CharT, Traits) \ test_readsome ((CharT*)0, (Traits*)0, #CharT, #Traits) if (rw_note (0 <= opt_char && 0 <= opt_char_traits, 0, __LINE__, "basic_istream>::readsome() " "tests disabled")) TEST (char, char_traits); if (rw_note (0 <= opt_char && 0 <= opt_user_traits, 0, __LINE__, "basic_istream>::readsome() " "tests disabled")) TEST (char, UserTraits); #ifndef _RWSTD_NO_WCHAR_T if (rw_note (0 <= opt_wchar && 0 <= opt_char_traits, 0, __LINE__, "basic_istream>::readsome() " "tests disabled")) TEST (wchar_t, char_traits); if (rw_note (0 <= opt_wchar && 0 <= opt_user_traits, 0, __LINE__, "basic_istream>::readsome() " "tests disabled")) TEST (wchar_t, UserTraits); #endif // _RWSTD_NO_WCHAR_T return 0; } /***********************************************************************/ int main (int argc, char *argv[]) { return rw_test (argc, argv, __FILE__, "istream.unformatted", "readsome", run_test, "|-char~ " "|-wchar_t~ " "|-char_traits~ " "|-UserTraits~ ", &opt_char, &opt_wchar, &opt_char_traits, &opt_user_traits, (void*)0 /* sentinel */); }